Erlang如何睡觉(晚上?)

时间:2014-07-31 08:55:09

标签: multithreading timer erlang scheduled-tasks otp

我想在Erlang服务器上每隔几个小时运行一次小清理过程。

我知道计时器模块。我在教程中看到了一个使用链式计时器的示例:sleep命令等待多天后发生的事件,我发现这很奇怪。据我所知,与其他语言相比,Erlang流程是独一无二的,但是流程/线程一次睡几天,几周甚至几个月的想法似乎很奇怪。

所以我开始着手了解睡觉的具体细节。我发现的最接近的是一篇博文,提到睡眠是通过接收超时实现的,但仍然存在这样的问题:

这些睡眠/类似睡眠的功能实际上做了什么?

我的进程是否会在睡眠时占用资源?有成千上万的休眠进程会使用尽可能多的资源,例如,成千上万的进程服务于一个什么都不做的递归调用?在进程中反复睡眠或长时间睡眠是否会导致性能下降? VM是否不断花费资源来查看结束进程睡眠的条件是否已经完成?

作为旁注,如果有人可以评论是否有更好的方式而不是一次暂停几小时或几天,我会感激不尽?

2 个答案:

答案 0 :(得分:2)

还有erlang:hibernate/3将进程放入"深度睡眠",最大限度地减少了内存使用量。

答案 1 :(得分:1)

这是任何erlang进程的业力:等待或死亡:o)

当一个进程产生时,它开始执行直到最后一个执行行,然后死掉,返回最后一次评估。

为了使进程保持活动状态,没有其他解决方案可以在永久结束的连续调用中递归循环。

当然有几种条件可以让它停止或睡眠:

  • 循环结束:进程收到一条告诉他的消息 停止递归
  • 接收集团:进程将等到消息 匹配接收块中的一个条目将在消息中发布 队列中。
  • VM调度程序暂时停止以允许访问CPU 到其他过程

在最后两种情况下,执行将在VM调度程序的负责下重新启动。

在等待时它不使用CPU带宽,但保持与开始等待时完全相同的内存布局。 Erlang OTP提供了一些方法,可以使用hibernate选项将内存布局降至最低(请参阅gen_serevr或gen_fsm的文档,但仅限于高级用法)。

创建一个以常规(或几乎常规)间隔触发进程的“信号”的简单方法是有效地使用带有timout的接收块(超时限制为65535 ms),例如:

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.

和用法:

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

<强> [编辑]

计时器模块是在单独进程中运行的标准gen_server。定时器模块中的所有功能都是公共接口,它们执行隐藏的gen_server:call或gen_server:强制转换到定时器服务器。这是隐藏服务器内部并允许进一步演进而不影响现有应用程序的常见用法。

服务器在内部使用一个表(ets)来存储它必须执行的所有操作以及每个计时器引用,并且它在需要时使用它自己的函数被唤醒(最后,VM必须处理这个? )。

因此,您可以在不影响计时器服务器行为的情况下休眠进程。休眠机制是

  • 棘手,请参阅hibernate/3 definition上的文档,你会看到你必须自己“重建”上下文,因为所有内容都从进程上下文中删除,并且元组(模块,函数,参数}由系统在需要时重启您的流程。
  • 在垃圾收集和流程重启中花费一些时间

这就是为什么我说它确实是一个需要很好理由才能使用的先进功能。