What is "cheaper"?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

What is "cheaper"?

Valentin Micic-6
Hi,

Usually, when I use erlang:send_after/3, but no longer need the “ordered" event, I issue a corresponding erlang:cancel_timer/1 to stop this event from being raised.

As an example, consider a following code snippet:

ReqRef = make_ref(),
SomeServerPid ! {request, {ReqRef, [arg1, arg2, . . ., argn]} ),
Ref = erlang:send_after( 5000, self(), {cancel, ReqRef} ),

receive
   {ReqRef, some_reply}
   -> 
       erlang:cancel_timer(Ref),
       some_reply
   ;
   {cancel, ReqRef}
   ->
        “Request Timeout!”
end

This is what I usually do, because I believed that it would be more cost effective to cancel the timer than to ignore the message ordered by send_after/3.
As I never really critically examined this claim, is there anyone that may have a different opinion regarding this.

Put differently, ensuring that no memory leak is possible (due to general nature of the code handling messages), would it be “cheaper" to ignore the message generated by send_after/3 instead of canceling it?

Kind regards

V/
Reply | Threaded
Open this post in threaded view
|

Re: What is "cheaper"?

Nalin Ranjan
On Thu, Mar 25, 2021, 5:44 PM Valentin Micic <[hidden email]> wrote:
Hi,

Usually, when I use erlang:send_after/3, but no longer need the “ordered" event, I issue a corresponding erlang:cancel_timer/1 to stop this event from being raised.

As an example, consider a following code snippet:

ReqRef = make_ref(),
SomeServerPid ! {request, {ReqRef, [arg1, arg2, . . ., argn]} ),
Ref = erlang:send_after( 5000, self(), {cancel, ReqRef} ),

receive
   {ReqRef, some_reply}
   -> 
       erlang:cancel_timer(Ref),
       some_reply
   ;
   {cancel, ReqRef}
   ->
        “Request Timeout!”
end

This is what I usually do, because I believed that it would be more cost effective to cancel the timer than to ignore the message ordered by send_after/3.
As I never really critically examined this claim, is there anyone that may have a different opinion regarding this.

Put differently, ensuring that no memory leak is possible (due to general nature of the code handling messages), would it be “cheaper" to ignore the message

How do we ignore the messages?

generated by send_after/3 instead of canceling it?

Kind regards

V/


नमस्ते।
नलिन रंजन
Reply | Threaded
Open this post in threaded view
|

Re: What is "cheaper"?

Valentin Micic-6

On 25 Mar 2021, at 14:59, Nalin Ranjan <[hidden email]> wrote:

On Thu, Mar 25, 2021, 5:44 PM Valentin Micic <[hidden email]> wrote:
Hi,

Usually, when I use erlang:send_after/3, but no longer need the “ordered" event, I issue a corresponding erlang:cancel_timer/1 to stop this event from being raised.

As an example, consider a following code snippet:

ReqRef = make_ref(),
SomeServerPid ! {request, {ReqRef, [arg1, arg2, . . ., argn]} ),
Ref = erlang:send_after( 5000, self(), {cancel, ReqRef} ),

receive
   {ReqRef, some_reply}
   -> 
       erlang:cancel_timer(Ref),
       some_reply
   ;
   {cancel, ReqRef}
   ->
        “Request Timeout!”
end

This is what I usually do, because I believed that it would be more cost effective to cancel the timer than to ignore the message ordered by send_after/3.
As I never really critically examined this claim, is there anyone that may have a different opinion regarding this.

Put differently, ensuring that no memory leak is possible (due to general nature of the code handling messages), would it be “cheaper" to ignore the message

How do we ignore the messages?

generated by send_after/3 instead of canceling it?

Kind regards

V/


नमस्ते।
नलिन रंजन


How does one ignore a message? Well, one way would be to receive a message, but do nothing with it (e.g. drop it).
Or at least this is what I meant by it. (Also, I thought that my reference to “no memory leak” would have been sufficient to hint that a receiving process will remove a message from its queue).

But, Culpa Mea — I should have formulated my question a bit better.
Thus, let me take another stab at it: what would be more efficient, canceling the timer (and thus avoiding generation of the message), or letting the send_after/3 generating (and runtime delivering) the message?
The answer should be considered relative to the "event ordering" process — will it spend more time canceling the message, or removing generated message from its queue)?


Kind regards

V/
Reply | Threaded
Open this post in threaded view
|

Re: What is "cheaper"?

Jesper Louis Andersen-2
In reply to this post by Valentin Micic-6
On Thu, Mar 25, 2021 at 1:14 PM Valentin Micic <[hidden email]> wrote:
Usually, when I use erlang:send_after/3, but no longer need the “ordered" event, I issue a corresponding erlang:cancel_timer/1 to stop this event from being raised.


Correctness is also a player in this. For some protocols, you absolutely want the cancellation to be there in order to avoid a stale message, though they tend to be hard to completely avoid (because the timer expiration and message send happens before the cancel is executed. The window is small, but present).

Another important point is the amount of timers you have running, and how quickly you start new timers. If your timer is for an hour, and you generate 100 timers a second, it runs up, quickly. It might be reasonably efficient to fire those timers into the void, but they also take up space while they are just sitting there.

Reply | Threaded
Open this post in threaded view
|

Re: What is "cheaper"?

Maria Scott
In reply to this post by Valentin Micic-6
Hi,

not sure about cheap, but...

> But, Culpa Mea — I should have formulated my question a bit better.
> Thus, let me take another stab at it: what would be more efficient, canceling the timer (and thus avoiding generation of the message), or letting the send_after/3 generating (and runtime delivering) the message?
> The answer should be considered relative to the "event ordering" process — will it spend more time canceling the message, or removing generated message from its queue)?

... it may happen that the timer expires and sends the message just before you cancel it. The message will then pollute your message queue. As such, you should react on the return of cancel_timer/1, if it returns false you may want to flush out that message.

But on another note, erlang:cancel_timer/1 is synonymous to erlang:cancel_timer/2 with options {async, false} and {info, true}, which results in a blocking operation that will wait for the cancellation to really "happen". You may look into option {async, true}, which will immediately return ok and not block the calling process. You will still have to take care of the possible message that may have been sent just before you cancelled the timer.

Kind regards,
Maria Scott
Reply | Threaded
Open this post in threaded view
|

Re: What is "cheaper"?

Valentin Micic-6


On 25 Mar 2021, at 16:26, Maria Scott <[hidden email]> wrote:

Hi,

not sure about cheap, but...

But, Culpa Mea — I should have formulated my question a bit better.
Thus, let me take another stab at it: what would be more efficient, canceling the timer (and thus avoiding generation of the message), or letting the send_after/3 generating (and runtime delivering) the message?
The answer should be considered relative to the "event ordering" process — will it spend more time canceling the message, or removing generated message from its queue)?

... it may happen that the timer expires and sends the message just before you cancel it. The message will then pollute your message queue. As such, you should react on the return of cancel_timer/1, if it returns false you may want to flush out that message.

But on another note, erlang:cancel_timer/1 is synonymous to erlang:cancel_timer/2 with options {async, false} and {info, true}, which results in a blocking operation that will wait for the cancellation to really "happen". You may look into option {async, true}, which will immediately return ok and not block the calling process. You will still have to take care of the possible message that may have been sent just before you cancelled the timer.

Kind regards,
Maria Scott

Thank you, Maria

All things considered, it appears to be “cheaper" not to cancel the timer (and thus generated event) when the timer values for are reasonably small (e.g. a few seconds), but desirable to do so (as Jasper suggested), when values for the timer are relatively high (in order to provide for a better memory utilisation used by erlang:send_after/3 scheduler). 


Kind regards

V/

Reply | Threaded
Open this post in threaded view
|

Re: What is "cheaper"?

Raimo Niskanen-11
On Thu, Mar 25, 2021 at 08:06:11PM +0200, Valentin Micic wrote:

>
>
> > On 25 Mar 2021, at 16:26, Maria Scott <[hidden email]> wrote:
> >
> > Hi,
> >
> > not sure about cheap, but...
> >
> >> But, Culpa Mea — I should have formulated my question a bit better.
> >> Thus, let me take another stab at it: what would be more efficient, canceling the timer (and thus avoiding generation of the message), or letting the send_after/3 generating (and runtime delivering) the message?
> >> The answer should be considered relative to the "event ordering" process — will it spend more time canceling the message, or removing generated message from its queue)?
> >
> > ... it may happen that the timer expires and sends the message just before you cancel it. The message will then pollute your message queue. As such, you should react on the return of cancel_timer/1, if it returns false you may want to flush out that message.
> >
> > But on another note, erlang:cancel_timer/1 is synonymous to erlang:cancel_timer/2 with options {async, false} and {info, true}, which results in a blocking operation that will wait for the cancellation to really "happen". You may look into option {async, true}, which will immediately return ok and not block the calling process. You will still have to take care of the possible message that may have been sent just before you cancelled the timer.
> >
> > Kind regards,
> > Maria Scott
>
>
> Thank you, Maria
>
> All things considered, it appears to be “cheaper" not to cancel the timer (and thus generated event) when the timer values for are reasonably small (e.g. a few seconds), but desirable to do so (as Jasper suggested), when values for the timer are relatively high (in order to provide for a better memory utilisation used by erlang:send_after/3 scheduler).

I am certainly not certain... ;-)

A cancel_timer/1 for a timer that is bound for the process that calls
cancel_timer/1 is comparatively efficient.  It is when you cancel some
other process' timer it gets harder to handle.

Processing a message always takes some time, but if you always receive any
message without matching, then ditching a bogus time-out message is not
much work.  But the message still has to be generated and received.

So the standard pattern
  case erlang:cancel_timer(Tref) of
      false -> receive {timeout, Tref, _} -> ok end;
      _ -> ok
  end
will, when cancelling your own timer be fairly lightweight regarding locks,
and mostly return the time left, so no receive is done.

My guess is that that normal case is cheap.  But if it is cheaper then
cancelling with {async,true} and ditching a time-out message in a receive
any loop you already have?   Hard to guess...

>
>
> Kind regards
>
> V/
>

Cheers
--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB