关于消息传递的一些注意事项

2021-03-22 06:19:38

消息传递一直是erlang的核心,虽然合理威尔记录了,但我们已经避免进入太多细节,以在实施时给我们更多的血统。没有什么可以阻止我们在博客帖子中描述它,所以让我们仔细看看!

Erlang流程通过发送彼此信号(不与Unix信号混淆)相互通信。有许多不同的种类和消息是最常见的。实际上,涉及更多进程的一切都在内部使用信号:例如,通过使所涉及的流程来回通信,直到它们在链接上缩短,链接/ 1函数。

这有助于我们避免大量的锁,并且可以自己制作一个有趣的博客,但现在我们只需要留意两件事:持续收到和处理allsignals(包括消息)后面,他们有一个定义的命令:

保证两个进程之间的信号才能按照他们的顺序到达。换句话说,如果处理A发送信号1,然后将2发送到处理B,则保证信号1以在信号2之前到达。

%%将监控信号发送到“PID”,请求A'下降'消息%%当`PID`死亡时。 MREF =监视器(进程,PID),%%向“PID”发送消息信号以及我们的“请求”PID! {self(),mref,请求},接收{mref,response} - > %%将噬魔仪信号发送给`pid`,然后删除%%对应'下降'可能具有%%的消息在此期间到达。 erlang:魔法员(MREF,[FLUSH]),{OK,RESPORTAY}; {'下降' ,mref,_,_,原因} - > {错误,原因}结束

由于死亡进程无法发送消息,我们知道响应必须达到任何最终'下降'消息,但没有保证订单'下降'消息可能会在响应之前到达,我们不知道是否响应是否已经到来,这将是非常讨厌的。

拥有一个定义的顺序节省了很多麻烦,并且不会出现成本,但保证在那里停止。如果多个进程为共同进程发送时,即使您将首先发送信号之一,它们也可以按任何顺序到达。例如,这一序列是法律和完全可能的:

幸运的是,全球订单很少需要,很容易强加自己(在分布式案例外):只需让所有涉及的各方都与Acommon进程同步。

发送消息很简单:我们尝试找到与进程标识符相关联的进程,如果存在一个,则将消息插入其信号队列。

在插入队列之前,始终复制消息。由于浪费的哮喘可能会听到它大大减少了垃圾收集(GC)延迟,因为GCNEver必须超越单一过程。 Hastbeen的非复制实现在过去尝试过,但它们结果是一个不好的契合,因为低延迟比纯粹的吞吐量重要的是,对于那种软实时系统来说,旨在构建。

默认情况下,消息将直接复制到接收过程中堆,但是当不可能的(或期望 - 请参阅Message_queue_data标志),而是veallocate在堆之外的消息。

内存分配使得这种“离堆”消息稍微昂贵,但对于接收大量消息的进程非常简洁。在复制消息时,我们不需要与接收器进行交互 - 只有在将其添加到队列时 - 而且由于进程唯一的方法可以看到消息是在接收表达式中呈映射时,GC不需要考虑诸多邮件进一步减少延迟。

向其他Erlang节点上的进程发送消息以相同的方式工作,尽管现在存在丢失消息的风险。只要编号为主动之间的分发链接,才能传递邮件“是要传递的,但是当链接下降时它会变得棘手。

在远程过程(或节点)上使用监视器/ 2将告诉您当此表达时,表现得好像过程已死(具有原因与Noconnection),但随着该消息并不总是有帮助:链接可能已在邮件已收纳后已死亡另一端,我们所知道的是,在我们之前,链接往往有任何最终的回应。

与其他一切都没有免费午餐,并且您需要决定您的应用方式如何处理这些方案。

人们可能猜测进程通过接收表达式接收消息,但接收是一个错误的一点。与所有其他信号一样,过程即原地处理它们在后台中,从信号队列移动到消息队列的接收消息。

接收搜索消息队列中的匹配消息(OrderThee到达),或者如果未找到NONE,则等待新消息。搜索消息队列而不是信号队列意味着它不必担心发送消息的进程,这大大提高了性能。

这种“选择性地接收”特定消息的能力非常方便:我们并不总是在我们可以决定与一条消息和围绕所有未处的消息手动凸出的信息,这肯定会令人讨厌。

如果queuematcheses {回复,结果}中的下一个消息,但如果没有匹配的消息,则立即完成,但如果没有匹配的消息,则必须在放弃之前全部行进。当有很多用于服务器的进程常见的众多常见的人时,这是昂贵的,因为接收表达式可以匹配,只需几乎可以完成以优化搜索本身即可匹配。

我们目前唯一的优化是为什么当我们知道在某个点之前无法存在的消息时,标志着研究.Let的Revisit Request-responatioom:

MREF =监视器(进程,PID),PID! {self(),mref,请求},接收{mref,response} - > erlang:魔法员(MREF,[FLUSH]),{OK,RESPORTAY}; {'下降' ,mref,_,_,原因} - > {错误,原因}结束

由于Monitor / 2创建的引用是全局唯一的,并且不能存在于此呼叫,并且接收仅匹配包含该reference的消息,我们不需要查看之前接收的任何消息。

这使得即使在具有荒谬LongMessage队列的进程中也使成语有效,但不幸的是,它不是我们在通用箱中可以做的事情。虽然您作为程序员可以确定,即使在没有参考的情况下,也必须遵循某个响应,例如通过使用您的序列号,编译器无法读取您的意图,并且必须假设您希望任何匹配的消息。

弄清楚上述优化是否已踢出令人讨厌。它需要检查光束组件,即使是你尚未假定它将由于一些恼人的限制而工作:

我们只支持一个消息位置一次:一个创建发布的函数,调用使用此优化的另一个函数,然后使用第一个引用接收到的另一个函数,最终将通过整个消息队列进行搜索。

它只在单个函数子句内工作:参考创建和接收需要彼此旁边,并且您不能调用通用接收助手的多功能。

我们已经在即将到来的OTP 24发行版中解决了这些缺点,并且凭借编译器选项可以帮助您发现它的应用位置:

- 模块(示例)。 - 导出([T / 2])。 T(PID,请求) - > %% example.erl:5:优化:参考标记%%消息队列位置MREF =监视器(进程,PID),PID! {self(),mref,请求},%% example.erl:7:Info:在example.erl中的%% monitor / 2创建的传递引用.erl:5 await_result(mref)。 await_result(mref) - > %% example.erl:10:优化:所有子句匹配功能参数1在功能参数1中获得{MREF,响应} - > erlang:魔法员(MREF,[FLUSH]),{OK,RESPORTAY}; {'下降' ,mref,_,_,原因} - > {错误,原因}结束。