How does Erlang sleep (at night?)

不问归期 提交于 2019-12-05 23:32:58

That is the Karma of any erlang process: it waits or dies :o)

when a process is spawned, it start executing until the last execution line, and die, returning the last evaluation.

To keep a process alive, there is no other solution to recursively loop in a never ending succession of calls.

of course there are several conditions that make it stop or sleep:

  • end of the loop: the process received a message which tell him to stop recursion
  • a receive bloc: the process will wait until a message matching one entry in the receive bloc is posted in the message queue.
  • The VM scheduler stop it temporarily to let access to the CPU to other processes

in the 2 last cases the execution will restart under the responsibility of the VM scheduler.

while waiting it uses no CPU bandwidth, but keeps the exact same memory layout it had when it started waiting. The Erlang OTP offers some means to reduce this memory layout to the minimum using the hibernate option (see the documentation of gen_serevr or gen_fsm, but it is for advanced usage only in my mind).

a simple way to create a "signal" that will fire a process at regular (or almost regular) interval is effectively to use receive block with timout (The timeout is limited to 65535 ms), for example:

on_tick_sec(Module,Function,Arglist,Period) -> 
    on_tick(Module,Function,Arglist,1000,Period,0).
on_tick_mn(Module,Function,Arglist,Period) -> 
    on_tick(Module,Function,Arglist,60000,Period,0).
on_tick_hr(Module,Function,Arglist,Period) -> 
    on_tick(Module,Function,Arglist,60000,Period*60,0).



on_tick(Module,Function,Arglist,TimeBase,Period,Period) ->
    apply(Module,Function,Arglist),
    on_tick(Module,Function,Arglist,TimeBase,Period,0);
on_tick(Module,Function,Arglist,TimeBase,Period,CountTimeBase) ->
    receive
        stop -> stopped
    after TimeBase ->
        on_tick(Module,Function,Arglist,TimeBase,Period,CountTimeBase+1)
    end.

and usage:

1> Pid = spawn(util,on_tick_sec,[io,format,["hello~n"],5]).
<0.40.0>
hello                
hello                
hello                
hello                        
2> Pid ! stop.
stop
3>

[edit]

The timer module is a standard gen_server running in a separate process. All the function in the timer module are public interfaces that execute a hidden gen_server:call or gen_server:cast to the timer server. This is a common usage to hide the internal of a server and allow further evolutions without impact on existing applications.

The server uses internally a table (ets) to store all the actions it has to do along with each timer reference and it uses its own function to be awaken when needed (at the end, the VM must take care of this ?).

So you can hibernate a process without any effect on the timer server behavior. The hibernation mechanism is

  • tricky, see documentation at hibernate/3 definition, you will see that yo have to "rebuild" the context by yourself since everything was removed from the process context, and a tuple(Module,Function,Arguments} is stored by the system to restart your process when needed.
  • cost some time in garbage collecting and process restart

It is why I said that it is really an advance feature that need good reason to be used.

There is also erlang:hibernate/3 that puts a process in "deep sleep", minimizing memory usage for it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!