Erlang 怎么睡觉(晚上?)

Posted

技术标签:

【中文标题】Erlang 怎么睡觉(晚上?)【英文标题】:How does Erlang sleep (at night?) 【发布时间】:2014-09-23 03:35:42 【问题描述】:

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

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

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

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

我的进程是否在休眠时占用资源?有数千个休眠进程会使用尽可能多的资源,例如,数千个进程服务于一个什么都不做的递归调用吗?在进程中反复休眠或长时间休眠是否会导致性能损失?虚拟机是否不断消耗资源来查看结束进程睡眠的条件是否成立?

作为旁注,如果有人可以评论是否有比睡觉更好的方法来一次暂停数小时或数天,我将不胜感激?

【问题讨论】:

在问题得到 2 个有用答案后的几个月内,是否愿意解释反对意见? 【参考方案1】:

这是任何 erlang 进程的因果报应:它等待或死亡 :o)

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

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

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

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

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

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

创建将定期(或几乎定期)间隔触发进程的“信号”的一种简单方法是有效地使用带有 timout 的接收块(超时限制为 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.

及用法:

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

[编辑]

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

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

因此,您可以使进程休眠,而不会影响计时器服务器的行为。休眠机制是

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

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

【讨论】:

"...在等待时它不使用 CPU 带宽,但保持与开始等待时完全相同的内存布局..."正是我想要的。它准确地解释了文档所指的暂停将花费多少。我不确定这是否值得另一个问题,所以我会在这里问,将进程发送到休眠状态会干扰像 send_interval 这样的调用,还是在当前进程之外处理? 实际上,看起来我在查看效率指南时部分回答了我自己的问题:“计时器模块使用单独的进程来管理计时器”,因此休眠不应影响 send_interval 的计时。但是 send_after 呢?它似乎也使用了计时器,但是根据同一文档,该计时器的功能与 send_interval 的计时器不同。【参考方案2】:

还有erlang:hibernate/3 将进程置于“深度睡眠”状态,从而最大限度地减少它的内存使用量。

【讨论】:

以上是关于Erlang 怎么睡觉(晚上?)的主要内容,如果未能解决你的问题,请参考以下文章

Erlang 源代码可以嵌入到 Elixir 代码中吗?如果是这样,怎么做?

erlang beam code文件怎么打开

Erlang 心跳

intellij idea 怎么编译erlang

Erlang:创建磁盘模式

Erlang 中的循环神经网络