面試中本身說話不利落, 或者本身對知識點認識不全面.在這裏進行一下記錄. 理論部分都是收集(copy)自網上其餘的博客.html
參與者模式(英語:Actor model)是一種併發運算上的模型。react
「參與者」是一種抽象概念,被視爲併發運算的基本單元:當一個參與者接收到一則消息,它能夠作出一些決策、建立更多的參與者、發送更多的消息、決定要如何回答接下來的消息。Actor模型的理念很是簡單:天下萬物皆爲Actor。面試
在使用Java進行併發編程時須要特別的關注鎖和內存原子性等一系列線程問題,而Actor模型內部的狀態由它本身維護即它內部數據只能由它本身修改(經過消息傳遞來進行狀態修改). redis
1.狀態(state):Actor中的狀態指的是Actor對象的變量信息,狀態由Actor本身管理,避免了併發環境下的鎖和內存原子性等問題編程
2.行爲(Behavior):行爲指定的是Actor中計算邏輯,經過Actor接收到消息來改變Actor的狀態併發
3.郵箱(mailBox):郵箱是Actor和Actor之間的通訊橋樑,郵箱內部經過FIFO消息隊列來存儲發送方Actor消息,接受方Actor從郵箱隊列中獲取消息. 異步
儘管許多actors同時運行,可是一個actor只能順序地處理消息。也就是說其它actors發送了三條消息給一個actor,這個actor只能一次處理一條。因此若是你要並行處理3條消息,你須要把這條消息發給3個actors。分佈式
消息異步地傳送到actor,因此當actor正在處理消息時,新來的消息應該存儲到別的地方。Mailbox就是這些消息存儲的地方。高併發
當一個actor接收到消息後,它能作以下三件事中的一件:性能
1. Create more actors; 建立其餘actors
2. Send messages to other actors; 向其餘actors發送消息
3. Designates what to do with the next message. 指定下一條消息到來的行爲
一個actor能維持一個私有狀態。「指定下一條消息來到作什麼」意味着能夠定義下條消息來到時的狀態。
設想有一個actor像計算器,它的初始狀態是數字0。當這個actor接收到add(1)
消息時,它並不改變它本來的狀態,而是指定當它接收到下一個消息時,狀態會變爲1。
1. 事件模型驅動--Actor之間的通訊是異步的,即便Actor在發送消息後也無需阻塞或者等待就可以處理其餘事情
2. 強隔離性--Actor中的方法不能由外部直接調用,全部的一切都經過消息傳遞進行的,從而避免了Actor之間的數據共享,想要觀察到另外一個Actor的狀態變化只能經過消息傳遞進行詢問.
3. 位置透明--不管Actor地址是在本地仍是在遠程機上對於代碼來講都是同樣的
4. 輕量性--Actor是很是輕量的計算元,只需少許內存就能達到高併發
5. 若是不用actor模型, 隨着項目體量增大,業務越發複雜,不可避免大量使用「鎖」,然而「鎖」的實際上是很耗性能的,因此大量使用鎖的機制確定會形成效率不高. 即便大量依賴「鎖」解決了系統中資源競爭的狀況,可是因爲沒有一個規範的編程模式,最後系統的穩定性確定會出問題,最根本的緣由是沒把系統的任務調度抽象出來,因爲任務調度和業務邏輯的耦合在一塊兒,很難作一個很高層的抽象,保證任務調度有序。
6.做爲開發者咱們只須要關心每一個Actor的邏輯就能夠了,避免「鎖」的「濫用」
當全部邏輯都跑在Actor中時,很難掌控Actor的粒度,稍有不慎就可能形成系統中Actor個數爆炸的狀況,Actor當出現必須共享數據或者狀態時就很難避免使用「鎖」,但彷佛因爲上面的「Actor可能會堵塞本身,但Actor不該該堵塞它運行的線程」準則衝突,這個時候也許能夠選擇使用redis作數據共享.
Actor模型有兩種任務調度方式:
1. 基於線程的調度:爲每一個Actor分配一個線程,在接收一個消息時,若是當前Actor的郵箱(mail box)爲空,則會阻塞當前線程。基於線程的調度實現較爲簡單,但線程數量受到操做的限制,如今的Actor模型通常不採用這種方式;
2. 基於事件的調度:事件能夠理解爲上述任務或消息的到來,而此時纔會爲Actor的任務分配線程並執行。
基於線程的調度爲每一個Actor分配一個線程,在接受一個消息(如在Scala Actor中使用receive)時,若是當前Actor的「郵箱(mail box)」爲空,則會阻塞當前線程直到得到消息爲止。基於線程的調度實現起來較爲簡單. 可是線程數量一多就會影響到系統資源佔用以及調度,而在某些狀況下大部分的Actor會處於空閒狀態,而大量阻塞線程既是系統的負擔,也是資源的浪費。所以現有的Actor Model大都不會採起這種方式。
基於事件的調度中, 「事件」在這裏能夠簡單理解爲「消息到達」事件,而此時纔會爲Actor的任務分配線程並執行, 既保證了運算資源的充分佔用,也不會讓系統在同時進行的太多任務中「疲憊不堪」,這樣系統即可以獲得很好的伸縮性。在Scala Actor中也能夠選擇使用「react」而不是「recive」方法來使用基於事件的方式來執行任務。
Erlang 引入了「隨它崩潰」的哲學理念,這部分關鍵代碼被監控着,監控者的惟一職責是知道代碼崩潰後幹什麼(如將這個單元代碼重置爲正常狀態),讓這種理念成爲可能的正是actor模型。
每段代碼都運行在process中,process是erlang稱呼actor的方式。這個process徹底獨立,意味着它的狀態不會影響其餘process。咱們有個supervisor,實際上它只是另外一個process(全部東西都是actor),當被監控的process掛了,supervisor這個process會被通知並對此進行處理。這就讓咱們能建立「自愈」系統了。若是一個actor到達異常狀態並崩潰,不管如何,supervisor均可以作出反應並嘗試把它變成一致狀態,這裏有不少策略,最多見的是根據初始狀態重啓actor。
關於actor模型的有趣方面是它並不在乎消息發送到的actor是本地的或者是另外節點上的。
轉念一想,若是actor只是一些代碼,包含了一個mailbox和一個內部狀態,actor只對消息作出響應,誰會關注它運行在哪一個機器上呢?只要咱們能讓消息到達就好了。這容許咱們基於許多計算機上構建系統,而且恢復其中任何一臺。
好比如今要在3臺物理節點上運行一個WordCount做業,能夠將這個做業細分爲Split、Count和Merge三種任務(任務的target是物理節點的地址,communication可能包含文本、單詞及計數等),根據需求要有Split Actor、Count Actor和Merge Actor。整個做業的處理流程如下:
1. Split Actor接收到消息後能夠文本分割成10份,每份發送給一個Count Actor;
2. Count Actor統計好單詞的數目後發送消息給Merge Actor;
3. Merge Actor收集完Count Actor發送的10個消息後,合併每一個單詞的數目,完成WordCount任務。
從以上例子能夠看出,Actor系統跟數據驅動系統好比數據流相近,能夠自定義任務的流向及其處理過程。
參考博客(就是copy+整理):
https://blog.csdn.net/gulianchao/article/details/7249117
https://www.cnblogs.com/lixiang-share/p/5829437.html