2013-08-02 56 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