Scala Actor與底層并發編程機制異同之探討
原創【51CTO精選譯文】前日,Akka 0.6發布了。Akka是一個基于Actor的框架,提供Scala API和Java API,目標是“通過Actor實現更簡單的伸縮性,容錯力,并發以及遠程操作”。
本篇文章的主題是Actor。對于不太了解Actor的讀者們,可以先參考一下老趙的這篇《Actor模型的本質》。簡單的說,Actor是一種天生為并行編程而存在的模型,在很多編程語言中都采用了這種模型,比如C#,Erlang以及Scala。本文是Code-o-matic博主Dimitris Andreou針對Scala的Actor模型展開的思考。
51CTO編輯推薦:Erlang的Actor回顧 順暢的使用C# Actor
有人在Scala郵件列表的討論中建議直接對比actors和鎖的使用。下文是我的討論,前面部分只是作為一種回應,而最后我總結了不少當前對于actor編程模型的關注點和問題。
將actors和底層并發編程(比如鎖)做對比具有誤導性。它不是這樣一種情況:存在一些actors,它們之后是巨大的空白,然后是一些鎖——然后我們不得不做出一些極端的選擇。兩者之間涉及更多的東西。例如,一臺虛擬機中,在阻塞隊列(或者,不久之后將成為的傳輸隊列)的頂端實現消息傳遞是非常煩瑣的。目前已經有executor框架,以及fork/join框架來提供線程池或者細粒度(fine-grained)的并行(parallelism)機制。(51CTO編輯推薦閱讀:Java 7的細顆粒并行化)
我要說的是,actors提供了一種簡單化的、比直接使用底層工具更簡潔優雅的編程模型。在其內核中,典型的actors是一種伴隨阻塞隊列(郵箱)的運行接口,而反應程序是事件的監聽者。正如Haller/Odersky論文中指出的那樣,actors的優勢在于它們能夠將基于線程和基于事件的模型統計起來——人們也可以在相同的架構下使用這兩種模型,或者對它們進行組合。這種編程模型目前正處于起步階段,還需要編程人員去探索以找到最佳的使用案例,并充分的理解它。頗為重要的是,你有必要準備一本“Effective Actors”這種類型的書。Actors編程很容易誤入歧途,尤其是對于那些試圖進行類MPI編程卻被搞得暈頭轉向的初學者而言更是如此。死鎖仍然存在(actors可能會永久等待一個不會到達的消息),競爭條件也可能出現(actors可能在真正的響應到達之前放棄等待),它不會像常規并發編程那樣,其可疑之處不會奇跡般的消失。(注明:根據JCiP命名規則(51CTO編輯注:JCiP即Java Concurrency in Practice,實用Java并發),我將最后一種情況歸為競爭條件或許是一個錯誤,因為它更像是一種數據競爭)
此外,簡化編程也必須付出代價,探討其對性能的影響變得不再像以前那么容易,至少對我而言如此。例如:假定scala actors依賴于ForkJoinScheduler(也就是使用fork/join架構), 此處源自ForkJoinPool中的javadocs的引用將會很有意思:
ForkJoinPool在創建時會被指定一個并行等級(目標池的大小),該等級通過動態添加、掛起、恢復線程的方法來維持,即使一些任務正在等待其它任務也是如此。然而,在阻塞式IO或者非托管的異步系統中,這種調整沒有被實現。
這就產生一些很明顯、但我卻很難告訴你答案的問題:
1. actors使用(阻塞式)IO會對性能產生什么影響?(我還沒有看到提供給actors用戶的類似警告)
2. 既然我們根據javadoc已經知道任務不會被加入,而receive()的阻塞式系統調用會陷入非托管的同步系統中,那么這對我們而言又意味著什么呢?
#t#因此,簡單化也似乎意味著以隱藏可能的重大優化作為代價,就像一個需要阻塞以加入子任務的線程一樣,在其等待期間繼續運行以及執行其它任務。
我不能確定最終的結論是什么。若順利的話,3-4年內社區在這一方面的編程經驗將會大大增加,我們將了解如何才能更好的使用這種很炫的工具,也將會知道什么時候改使用底層的并發服務程序。就我個人而言,截至目前為止,盡管我很希望使用actors,但底層工具的運用讓我如魚得水,因為我可以更容易分析我的代碼的性能特征。很希望有人能夠寫一本優秀的Scala actors書籍——雖然目前并發的書也不錯,但因為Scala還很新,所以這些數據關于actors的往往只有一章。讀者若想了解除基礎知識之外的東西,這些書籍所涵蓋的內容還遠遠不夠。
【51CTO.com譯稿,非經授權請勿轉載。合作站點轉載請注明原文譯者和出處為51CTO.com,且不得修改原文內容。】
原文:Thoughts on Actors 作者:Dimitris Andreou