1. 程式人生 > >二 Akka學習 - actor介紹

二 Akka學習 - actor介紹

應用程序 很多 數據庫驅動 actor 取出 操作 osc 輔助 col

一個actorSystem 是一個重量級的結構。它會分配N個線程。所以對於每一個應用來說只用創建一個ActorSystem。

Actor是種可憐的“生物”,它們不能獨自存活。Akka中的每一個Actor都是由一個Actor系統(Actor System)來創建和維護的。一個Actor系統會提供一整套輔助功能,

樹形結構

actors以樹形結構組織起來,類似一個生態系統。例如,一個actor可能會把自己的任務劃分成更多更小的、利於管理的子任務。為了這個目的,它會開啟自己的子actor,並負責監督這些子actor。關於監督的具體細節就不在這裏討論了。我們只要知道一點,就是每一個actor都會有一個監督者,那就是創建這些actor的那個actor。

如下圖:

技術分享圖片

actor系統的精華就是任務的分解。任務要被分割的要足夠小,每個分片都會被委托給子actor。這裏用到的思想很明顯就是“分而治之”,萬變不離其宗啊!要想做好這一切,不僅僅要把任務組織的非常清晰(利於分解),也要對處理任務的最終actor在以下方面進行考慮:哪些消息需要處理、如何正常的回應、如何處理失敗等等。如果一個處理特定任務的actor失敗了,它會向它的監督者發出響應錯誤的消息去尋求錯誤處理的方法。這種遞歸式(監督者也有自己的監督者)的結構可以保證錯誤在合適的級別上進行處理。

你的應用程序是由幾十個還是幾百萬個Actor來組成取決於你的用例,但是Akka完全有能力處理百萬級別數量的Actor,你可能覺得創建這麽多Actor一定是瘋了,但實際上,Actor和線程之間並不是一一對應的關系,這一點非常重要,否則系統的內存很快就會被耗光的。由於Actor的非阻塞特性,一個線程可以為不同的Actor服務,Akka(譯者註:具體地說是Dispatcher)會讓線程在不同的Actor之間切換,依據是當前誰有消息需要被處理就分配線程給它。為了了解實際發生了什麽。

消息的發送和處理完成是一個異步的非阻塞的過程。發送方不會一直被阻塞到接收方處理完消息,它會直接繼續它自己的工作,發送方可能會期望從處理方那裏得到一個反饋消息,但也許它根本不關心消息的處理結果。當某些組件發送一條消息給一個Actor時,真正發生的事情是:這個消息被投遞給了這個Actor的Mailbox, 我們基本上可以把Mailbox當成一個對列。把一條消息放到一個Actor的Mailbox的過程也是非阻塞的,比如:發送方不會一直等待消息進入接收方的Mailbox對列。

Dispatcher會通知Actor它的Mailbox有一條新消息,如果這個Actor正在處理著手頭上的消息,Dispatcher

會從當前的執行上下文裏選一個可用的線程,一旦Actor處理完前面的消息,它會讓Actor在這個準備好的線程上從Mailbox裏取出這條消息去處理。Actor會阻塞分配給它的線程直到它開始處理一條消息,但這並不會阻塞消息的發送方,這意味著一個耗時較長的操作會影響整體的性能,因為所有其他的Actor不得不被安排從剩余線程中選取一個去處理消息(譯者註:增加了線程調度的開銷)。

因此,你的Receive偏函數要遵從一個核心的準則:盡可能地縮短它的執行時間(譯者註:可以把任務分解為更小的單元委派更粒度更細的Actor去執行)。更重要的是,在你的消息處理代碼裏盡量地避免調用會造成阻塞的代碼。當然,有些事情是你無法完全避免的,比如,當今主流的數據庫驅動基本都是阻塞的,如果你想讓你的程序基於Actor去持久化或查詢數據時,你就會面臨這樣的問題。現在已經有一些應對這類問題的方案了,但是作為一偏介紹性的文章,本文先不涉及。

如何創建一個actor實例?

用new方法?這樣不行!Akka會用一個ActorInitializationException異常回敬你。事情是這樣的:為了能讓Actor良好地工作,你的Actor必須交給ActorSystem和它的組件來托管。因此,你需要通過ActorSystem來幫你創建這個實例

義在AcotorSysytem上actorOf方法期望一個Props實例,針對新建的Actor的配置信息都會封裝到這個Props實例裏,

註意:actorOf返回的對象類型不是Barista而是ActorRef(譯者註:Akka對Actor的托管體現在很多地方,前面提到的你不能直接創建一個Actor實例是一方面,此處,創建之後你得到的也不是Actor實例本身而是一個ActorRef)。Actor從不會與其他Actor直接通信,因此沒有必要獲取一個Actor實例的直接引用,而是讓Actor或其他組件獲取那些需要發送消息的Actor的ActorRef

因此,ActorRef扮演了Actor實例代理的角色,這樣做會帶來很多好處,因為一個ActorRef可以被序列化,我們可以讓它代理一個遠程機器上的Actor,至於ActorRef後面的這個Actor是本地JVM裏的還是一個遠程機器上的,這對使用者來說都是透明的,我們把這種特性稱作“位置透明”。

請記住,ActorRef不是類型參數化的,任何ActorRef都可以互相交換,以便可以讓你發送任意的消息給任意的ActorRef。這種設計我們前面也提到了,它讓你可以簡單地修改你的Actor系統的網絡拓撲而不需要對發送方做任何修改。

問詢(Ask)機制:

有時候,給一個Actor發送消息然後期待返回一個響應消息這種模式並不適用於某些場景,最常見的例子是當某些組件並不是Actor但又需要和Actor交互時,它們就無法接收來自Actor的消息。對於這種情況,Akka有一種Ask機制,它在基於Actor的並發和基於Future的並發之間提供一座橋梁

二 Akka學習 - actor介紹