http://www.infoq.com/cn/news/2009/01/actor-in-groovy
性能是所有程序開發人員無法迴避的問題,性能糟糕的程序只會將客戶拒之門外,讓開發商的聲譽受損,讓投資人的金錢打水漂。然而優秀的性能表現並非能免費獲得,即便在當今的多核時代,一個單線程程序也不會因部署到多核機器上而使性能自動提升。不錯,在衆多提升性能的手段中,使程序並行化是其中最容易想到且最有效的手段之一。然而對於大多數主流編程語言來講,“說來容易,做起來難”這句老話在多線程編程上可謂體現得淋漓盡致。以Java這一無所不在的語言爲例,死鎖、資源分配、狀態共享、調試、異步調用無一例外都是在多線程編程過程中的攔路虎。這一點想必有過Java多線程編程經驗的開發者都有體會。而隨着並行需求的越來越高,另一門有着悠久歷史的語言也重新得到了主流世界的關注,它就是Erlang。
Erlang以其對並行編程天生的支持而聞名。在其他語言看來棘手的並行編程問題,對Erlang來說則顯得是輕而易舉。由於無共享、基於消息等特點,使得死鎖、狀態共享、異步調用等困擾多線程編程的問題在Erlang中不復存在。正是因爲使用它編寫並行程序容易,使得這些年來國內技術社區對Erlang的關注在不斷地升溫。當然,任何一門成功語言的背後都離不開堅實的理論基礎。Erlang也不例外。支撐其對並行編程有着良好支持的幕後功臣要歸功於Actor模型。
Actor模型並非什麼新鮮事物,它由Carl Hewitt於上世紀70年代早期提出,目的是爲了解決分佈式編程中一系列的編程問題。其特點如下(摘自這個幻燈片):
- 系統中的所有事物都可以扮演一個Actor
- Actor之間完全獨立
- 在收到消息時Actor所採取的所有動作都是並行的,在一個方法中的動作沒有明確的順序
- Actor由標識和當前行爲描述
- Actor可能被分成原始(primitive)和非原始(non primitive)類別
- 非原始Actor有
- 由一個郵件地址表示的標識
- 當前行爲由一組知識(acquaintances)(實例變量或本地狀態)和定義Actor在收到消息時將採取的動作組成
- 消息傳遞是非阻塞和異步的,其機制是郵件隊列(mail-queue)
- 所有消息發送都是並行的
幸運的是,Erlang並非是實現了Actor模型的唯一語言。在Java平臺上,開發者還能夠選擇Scala。對於那些堅守“純”Java語言的開發者,他們則可以選擇以下的框架:
關於這些框架的比較,可以參見這個帖子。
- send,發送消息
- receive,接收消息
- start,啓動Actor
- act,該方法是protected類型的,它由Actor的線程週期調用,直到Actor上的stop被調用爲止。GParallelizer提供了一種“即發即棄”的Actor:OneShotActor,它的stop方法會在首次執行act之後自動被調用。
- stop,停止Actor
Actor上的生命週期方法有:
- afterStart
- beforeStop
- afterStop
Vaclav Pech並在其博客對Actor的主要使用進行了說明。
創建一個打印它收到的所有消息的一個Actor。
def actor = Actors.actor { println receive() }
啓動併發送消息。
actor.start() actor.send('Message')
擴展Actor。
class CustomActor extends BoundedActor { @Override protected void act() { println receive() } } def actor=new CustomActor()
除了這些入門的例子,Vaclav Pech還列舉了相對實用的兩個例子:計算器和並行歸併排序。關於這些例子的詳情可以從其博客瞭解一二。
除了Actor,GParallelizer的主要組件還包括:
- Asynchronizer,基於Java Executors的並行集合處理器
- Parallelizer,使用JSR-166y並行數組(Parallel Arrays)來對多線程集合處理提供支持。