閱讀505 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Akka筆記之Actor簡介

寫過多線程的人都不會否認,多線程應用的維護是件多麼困難和痛苦的事。我說的是維護,這是因為開始的時候還很簡單,一旦你看到性能得到提升就會歡唿雀躍。然而,當你發現很難從子任務的錯誤中恢複或者有些僵屍BUG很難複現再或者你的分析器顯示你的線程在寫入一個共享狀態前大部分時間都浪費在阻塞上麵的時候,痛苦降臨了。

我刻意沒提Java的並發API,以及它裏麵的集合類使得多線程編程變得多麼輕鬆簡單,因為我相信既然你們點進了這篇文章,那就說明你希望能更好地控製你的子任務,或者你就是不喜歡使用鎖以及同步塊,希望能有一種更高層次的抽象。

在本係列的Akka筆記中,我們將通過一些簡單的Akka例子來體驗下它的諸多特性。

什麼是Actor?

Akka中的Actor遵循Actor模型。

你可以把Actor當作是人。這些人不會親自去和別人交談。他們隻通過郵件來交流。

我們來稍微解釋下這點。

1. 消息傳遞

假設有兩個人——一個聰明的老師和一個學生。學生每天早上都會發一封郵件給老師,而老師則會回複一句名言。

需要注意的地方:

1. 學生發送郵件。一旦發送成功,郵件不能再修改。這天然就具備了不可變性。
2. 老師會自己決定何時檢查郵箱。
3. 老師還會回複一封郵件。
4. 學生會自己決定何時檢查郵箱。
5. 學生不會一直等待回信(非阻塞的)。

這就可以總結出Actor模型的一個基本特征——消息傳遞。

消息傳遞

2. 並發

現在,想像一下3個聰明的老師和3個學生——每個學生都會向所有老師分別發送筆記。這會發生什麼?事實上沒有任何改變。每個人都有自己的郵箱。這裏有一點值得強調一下:

默認情況下,郵箱中的郵件是按它們到達的順序進行處理的。

本質上這就是一個ConcurrentLinkedQueue](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html)。由於沒有人在等待郵件,這就是一個非阻塞的消息。(Akka[內置包含許多種郵箱實現,包括有界的以及基於優先級的)。事實上,我們自己也能開發一個。

多人間的消息傳遞

3. 失敗處理

想像下這三個老師是不同係的——曆史,地理以及哲學。

曆史老師對過去的某個事件進行了評論,地理老師則發送了一個很有意思的地方,而哲學老師回複了一句名言。每個學生都分別給各個老師發送郵件並收到回信。學生並不關心郵件到底是係裏的哪個老師回複的。如果有一天有個老師生病了呢?係裏至少得有一個老師在處理郵件才行。這樣的話,係裏的另一位老師就會頂上這項工作。

需要注意的地方:

1. 會有一個Actor的池,每個Actor會處理不同的事件。
2. Actor做的事情可能會拋出異常。它自己無法從中恢複。這種情況下,需要再生成一個新的Actor來頂替它。換句話說,這個新的Actor會忽略剛才那條消息,繼續處理剩餘的消息。這些也被稱為指令(Directive),後麵我們會再講到它們。

4. 多任務

我們假設下每個老師都會通過郵件來發送考試成績,如果學生這麼要求的話。類似的,Actor也可能會處理多種類型的消息。

5. 消息鏈

那如果學生不想收到多封郵件,而是一封該怎麼辦呢?

Actor同樣可以完成這個。我們可以將老師進行分層。後麵我們講到Supervisor和Future的時候會再回來講下這點。

應Mohan的要求,我們把類比的實體和Actor模型中的組件做一下映射。

學生和老師都是我們的Actor。收件箱就是Mailbox組件。請求和響應是不可修改的。它們都是不可變對象。最後,Actor中的MessageDispatcher組件會管理郵箱並將消息路由到對應的Mailbox中。

說得夠多的了,我們來寫下代碼吧…

未完待續…

本文最早發布於我的個人博客: Java譯站

最後更新:2017-05-23 14:35:25

  上一篇:go  華棲雲與阿裏雲首推“雲上電視台”,可實現內容雲端一站式製作
  下一篇:go  Akka筆記之消息傳遞