Erlang 如何睡觉(晚上?)

Sel*_*bor 5 erlang multithreading timer scheduled-tasks erlang-otp

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

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

因此,我开始了解睡眠的具体作用。我发现的最接近的是一篇博客文章,提到睡眠是通过接收超时实现的,但这仍然留下了问题:

这些睡眠/类似睡眠的功能实际上有什么作用?

我的进程在休眠时是否占用资源?数千个休眠进程是否会使用同样多的资源,例如,数千个进程为不执行任何操作的递归调用提供服务?在进程内反复休眠或长时间休眠是否会造成性能损失?VM是否不断消耗资源来查看结束进程睡眠的条件是否成立?

作为旁注,如果有人能评论一下是否有比睡觉更好的方法,一次暂停几个小时或几天,我将不胜感激。

Pas*_*cal 2

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

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

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

当然有几个条件让它停止或者休眠:

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

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

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

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

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.
Run Code Online (Sandbox Code Playgroud)

和用法:

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

[编辑]

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

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

因此,您可以休眠进程,而不会对计时器服务器行为产生任何影响。休眠机制是

  • 棘手,请参阅hibernate/3 定义中的文档,您将看到您必须自己“重建”上下文,因为所有内容都已从进程上下文中删除,并且系统存储了一个元组(模块,函数,参数}以重新启动需要时您的流程。
  • 花费一些时间进行垃圾收集和进程重启

这就是为什么我说它确实是一个高级功能,需要充分的理由才能使用。