2013-08-02 53 views

回答

4

您的代码无法崩溃,因为所有进程都是本地的

B = spawn_link(fun() -> receive P -> P ! m2 end end),  % 1 
A = spawn_link(fun() -> receive X -> X=m1 end end),  % 2 
A ! m1,             % 3 
B ! A.             % 4 

当评估线3,既BEAM仿真器和HIPE调用erl_send内置函数(BIF)。由于A是本地进程,因此erl_send(实际上是do_send)最终会调用erts_send_message其中enqueues邮箱中的邮件。在SMP模式下,线程实际上获得了邮箱的锁定。

因此,在评估第4行并将A发送给进程B时,A的邮箱中已经有m1。所以m2只能在m1后排队。

这个结果是否与Erlang的当前实现特别有关是有争议的,即使这不是由文档保证的。的确,每个进程都需要一个邮箱,并且需要以某种方式填写该邮箱。这是在第3行同步完成的。要异步执行,每个进程需要另一个线程或多个邮箱(例如,每个调度程序一个邮箱以避免锁定邮箱)。但我认为这不会在表现方面有意义。

如果进程A和B是远程的,但在同一节点内,行为稍有不同,但结果与当前的Erlang实现相同。在第3行,消息m1将被排入远程节点,并且在第4行,消息A将在之后被排队。当远程节点将消息出队时,在将A写入B的邮箱之前,它首先将m1写入A的邮箱。

如果过程A是远程的,B是本地的,结果仍然是一样的。在第3行,消息m1将被排入远程节点,并且在第4行,消息将被写入B,但是随后在第1行,消息m2将在m1之后被排队到远程节点。所以A会以m1,m2的顺序得到消息。

同样,如果进程A是本地的,而B是远程的,则A会在第3行将消息复制到第3行的邮箱中,然后通过网络将任何内容发送到B的节点。

在当前版本的Erlang中,导致崩溃的唯一方法是在不同的远程节点上使用A和B.在这种情况下,前A排入到B的节点m1排入到A的节点。但是,这些消息的传递不同步。例如,如果许多消息已经排队等待A的节点,则可以首先发送到B的节点。

下面的代码(有时)通过填充队列到A的节点与垃圾消息的m1交货慢触发崩溃。

$ erl -sname [email protected]

C = spawn_link(fun() -> 
    A = receive {process_a, APid} -> APid end, 
    B = receive {process_b, BPid} -> BPid end, 
    ANode = node(A), 
    lists:foreach(fun(_) -> 
     rpc:cast(ANode, erlang, whereis, [user]) 
    end, lists:seq(1, 10000)), 
    A ! m1, 
    B ! A 
end), 
register(process_c, C). 

$ erl -sname [email protected]

B = spawn_link(fun() -> receive P -> P ! m2 end end), 
C = rpc:call([email protected], erlang, whereis, [process_c]), 
C ! {process_b, B}. 

$ erl -sname [email protected]

A = spawn_link(fun() -> receive X -> X = m1 end, io:format("end of A\n") end), 
C = rpc:call([email protected], erlang, whereis, [process_c]), 
C ! {process_a, A}. 
1

如果这两个过程都是同一节点上,这是真的,一个是保证M2之前得到M1。

但是,当两个进程是在不同的节点,它不能保证。

有关于这个问题的论文Programming Distributed Erlang Applications: Pitfalls and Recipes

这里是链接:http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.116.9929&rep=rep1&type=pdf

您的问题是在本文的2.2,我认为这是一个真正的intereting纸!

+0

为什么你认为它是保证在同一个节点上的进程?在那篇文章中,答案似乎是“可能”。 – Dog

+0

@Dog在另一篇名为“分布式Erlang的语义”的文章中,据说_Messages是即时传递的。 'm1'保证在'm2'之前到达同一个节点。这里是链接:http://www.erlang.org/workshop/2005/ErlangSemantics.pdf – Taotaotheripper

+0

但是我们不应该依赖于这一点,我想。 – Taotaotheripper