我們常常能在 Erlang 的文檔和源碼之中看到Ulf Wiger這個名字,他是 Erlang 最初的開發者之一。最近他寫了一篇博客《What is Erlang-Style Concurrency?》對于“Erlang風格的并行”發表了自己的看法,粗淺譯來,給大家共享。
原文:http://ulf.wiger.net/weblog/?p=10
譯文:http://erlang-china.org/news/erlang-style_concurrency.html
譯者:jackyz
現下時不時都能看到“用 language X 來做 Erlang 風格的并行”這樣的博客文章。我想這是好事,這表明大家都開始認真研究有關并行的問題了。
然而,對于“Erlang 風格的并行”這一術語,仍然缺乏一個權威的定義。我在這里嘗試給出自己的定義。
Joe Armstrong在他的《Programming Erlang》中寫了這么一段話:
“在Erlang中:
進程的創建和銷毀非常迅速
進程之間傳遞消息非常迅速
進程的行為獨立于操作系統
進程可以有大規模使用
進程之間徹底獨立不共享內存
進程之間交互的唯一途徑就是消息傳遞”
可以將這看作是一個“權威定義”,但稍嫌不夠完整。
我想再加上這么幾條:
- 消息傳遞是異步的
- 進程可以彼此監控
- 可以選擇性的接收消息
- 遠程進程和本地進程基本保持一致
上面的這些條目概略的描述了 Erlang 中并行的工作方式。那么,對于“Erlang 風格的并行”,是否這些條目全都是不可或缺呢?也許并非如此。
我想下面的這些特性都是必須的:
- 迅速的進程創建和銷毀
- 不費力的支持至少10K以上的并行進程
- 迅速的異步消息傳遞
- 復制的消息傳遞機制(無共享的并行)
- 進程監控
- 選擇性的消息接收機制
稍作解釋:
速度和伸縮性
要讓并行成為一種具有實用價值的基本建模手段,必須要讓程序員能放心的創建解決問題所需的大量進程,而無需擔心會因此而影響效率。若要以一句話來概況“Erlang 風格并行”的精髓,那就是——它讓你可以按照問題自身內在的并行模式來構建應用。如果認為創建進程代價高昂,程序員就會盡量重用已有的進程;如果認為消息傳遞代價高昂,就會發明出其它的技術以避免傳遞消息。而這些手段通常是有害的(對于并行來說)。
凡事都有自己的局限。Erlang 被設計用來于做“代理風格”的并行,而不是大數據量的并行。在 Erlang 中你“只能”有約 120M 個并行進程,如果內存足夠的話。我本人試過,在 20M 個并發進程時,Erlang 仍然保持一貫的性能(我當時沒有更多的內存可以繼續嘗試)。對于某些極端應用來說,(約5-10微秒)創建一個進程的代價仍嫌昂貴,但相比UNIX進程或 POSIX線程,至少“廉價”了幾個數量級。“Erlang 風格的并行”在進程的粒度上,應與 Erlang 大體保持一致。
異步消息傳遞
對于異步或者同步的消息傳遞,孰優孰劣曾經有過爭論。的確,同步消息傳遞更易于理解。但在分布式的環境下,異步通訊(也就是所謂的“發送-祈禱”)則更符合直覺。基于同步消息傳遞的系統,在分布式的環境下也必須訴諸于某種形式的異步通訊機制,方可完成任務。盡管仍然存在爭議,但無論如何異步消息傳遞仍是 “Erlang 風格并行”的一個特征。
復制機制
注意,這里的并不意味著說在所有的情況下都必須要完全復制所有的消息,重點不在方式,而在效果。這很重要,
主要原因如下:
- 從可靠性角度考慮,進程不能共享內存
- 在分布的環境下,復制不可避免,我們盡可能的在本地和遠程的消息傳遞中都保持相同的機制
要求進程之間不能共享任何東西,這可能太過嚴格,很有可能會將大部分的編程語言都被排除在“Erlang 風格的并行”之外(甚至連Scala這樣的語言都預留了在進程之間共享數據的可能)。那么好吧,我們至少應該說,Erlang 風格使得用非共享的方式來實現并行要比共享方式更為容易。
進程監控
這是“邊界外”錯誤處理機制的根基。在 Erlang 中,典型的錯誤處理哲學是——讓它崩潰。其要義就在于,你的程序只處理正常情況,出現異常的情況則交由監控進程來負責處理。這么做的結果是,在大型系統中,能漂亮的實現容錯。
選擇性的消息接收
有N中方法可以實現選擇性的消息接收,但對于復雜的多路并行而言,你必須至少要支持其中的一種。在達致并發的路上,這一點很容易被忽視。簡單的程序之中,你也不會很明顯的感到它的必要,但若當你真正發現它的價值,你很可能已經被“復雜性爆炸”折磨很久了。
我建議將選擇性的消息接收機制列為 Erlang 風格并發的一個充分條件。它可以通過對單一消息隊列進行匹配的方式(Erlang, OSE Delta)來實現,也可以通過多郵箱/頻道的方式(Haskell, .Net, UNIX 套接字)來實現。選一個,找個合適的例子,演練它,體驗它。如果你愿意,可以參照我的“Structured Network Programming”演示。
—樸素的分隔線—
注:跟隨這個鏈接你會發現“Erlang-Style Concurrency”正在迅速變成一個“即將臭大街”的名詞,也許正是擔心這種狀況的出現,Ulf Wiger 發表了這篇博客,對于一些聲稱自己是 Erlang-Style 的 tricky ,劃出了一道明確的標準,以正視聽。只是后續的發展到底如何,還需繼續觀察。
譯后 blah :
記得曾在 maillist 見到 Joe Armstrong 說過“Erlang(語言) 的力量不在語言,Erlang 是很淺顯的語言,而是在于語言和虛擬機之間的高度適配”。spawn一個進程,選擇性的從隊列中取出一條消息,或者以copy的方式發送一個異步消息,這些都不難做到,基本上哪個語言都能做到;難的部分就在于將這些部分在虛擬機中不斷打磨,以“極廉價的操作”為目標來高度優化,讓其走出珠寶店,進入菜市場,成為編寫程序時的一個可選常規工具;我們所使用的工具,它的特性,會反過來影響我們看待問題的方式。當它改變我們對系統建模的思維方式,并形成自己的一套思維模式時,即由此延生出了所謂的 COP 思想。這就是 Erlang 或者說 COP 所走過的路。類似 Scala 或其它以并發為設計目的之一的語言,若想達致 COP 的實用境界,很可能也必須要歷經這個痛苦鍛造過程的各個階段。而對于 COP 思想來說,也將會增加一個新的具有實用價值的實踐平臺。