一.Actor模型介紹
在單核 CPU 發(fā)展已經(jīng)達(dá)到一個(gè)瓶頸的今天持搜,要增加硬件的速度更多的是增加 CPU 核的數(shù)目。而針對(duì)這種情況,要使我們的程序運(yùn)行效率提高宏娄,那么也應(yīng)該從并發(fā)方面入手。傳統(tǒng)的多線程方法又極其容易出現(xiàn) Bug 而難以維護(hù)逮壁,不過別擔(dān)心孵坚,今天將要介紹另一種并發(fā)的模式能一定程度解決這些問題,那就是 Actor 模型窥淆。
Actor 模型其實(shí)就是定義一組規(guī)則卖宠,這些規(guī)則規(guī)定了一組系統(tǒng)中各個(gè)模塊如何交互及回應(yīng)。在一個(gè) Actor 系統(tǒng)中忧饭,Actor 是最小的單元模塊扛伍,系統(tǒng)由多個(gè) Actor 組成。每個(gè) Actor 有兩個(gè)東西词裤,一個(gè)是 mailbox刺洒,一個(gè)是自身狀態(tài)。同時(shí) Actor 有接收和發(fā)送的功能吼砂。下面代碼給出一個(gè)大概的 Actor 樣例:
trait Actor {
//持有一個(gè)表示自身狀態(tài)的私有變量
val state:Integer = 0;
//持有一個(gè)mailbox 的隊(duì)列
val mailBox:mutable.Queue[Message] = scala.collection.mutable.Queue[Message]()
def send(message : Message): Unit ={
...
}
def recive(): Unit ={
...
}
}
當(dāng)一個(gè) Actor 接收到消息后逆航,它會(huì)執(zhí)行下面三種操作中的一種:
- 創(chuàng)建其他actors。
- 向其他actors發(fā)送消息渔肩。
- 修改自身狀態(tài)因俐。
需要注意的是,盡管許多actors同時(shí)運(yùn)行周偎,但是一個(gè)actor只能順序地處理消息抹剩。也就是說其它actors發(fā)送了三條消息給一個(gè)actor,這個(gè)actor只能一次處理一條蓉坎。所以如果你要并行處理3條消息吧兔,你需要把這條消息發(fā)給3個(gè)actors。
下面這張圖展示了一個(gè)簡(jiǎn)單的 Actor 模型系統(tǒng):
了解了 Actor 模型的大概規(guī)則后袍嬉,我們用兩個(gè)具體的例子來看看 Actor 模型的妙處以及不足吧境蔼。
二. 兩個(gè)例子
2.1 素?cái)?shù)計(jì)算
假設(shè)我們現(xiàn)在有一個(gè)任務(wù)灶平,需要找出100000以內(nèi)素?cái)?shù)個(gè)數(shù),并且使用多線程的方式實(shí)現(xiàn)箍土。
下圖展示了使用共享內(nèi)存的方式和以Actor模型的方式進(jìn)行并發(fā)執(zhí)行逢享。
這里展示了兩種處理并發(fā)的不同思路,傳統(tǒng)的方式是通過鎖/同步的方式來實(shí)現(xiàn)并發(fā)吴藻,每次同步獲取當(dāng)前值瞒爬,并讓一個(gè)線程去判斷值是否為素?cái)?shù),是的話再通過同步的方式對(duì)計(jì)數(shù)器加1(這里的說明只是作為提供思路用沟堡,這種方法自然有很大的優(yōu)化空間)侧但。
而使用 Actor 模型則不一樣,它將這一過程拆分成幾個(gè)模塊航罗,即拆分成幾個(gè) Actor 禀横。每個(gè) Actor 負(fù)責(zé)不同的部分,通過消息傳遞的方式讓這幾個(gè) Actor 協(xié)同工作粥血,并且其中涉及到主要計(jì)算的 Actor 可以有多個(gè)柏锄,通過多個(gè) Actor 協(xié)同工作實(shí)現(xiàn)并發(fā)。
2.2 銀行轉(zhuǎn)賬
銀行轉(zhuǎn)賬的任務(wù)描述很簡(jiǎn)單复亏,假設(shè)有兩個(gè)用戶趾娃,現(xiàn)在用戶A向用戶B轉(zhuǎn)賬100元,這個(gè) Actor 模型該如何設(shè)計(jì)呢缔御?
用戶 A 和 用戶 B 明顯是兩個(gè) Actor 抬闷,但我們同時(shí)還需要一個(gè)可以控制用戶A Actor 和用戶B Actor 的 Actor ,我們稱之為 轉(zhuǎn)賬管家 Actor耕突。那么流程圖如下笤成。
可以看到,當(dāng)一個(gè)轉(zhuǎn)賬需求過來的時(shí)候有勾,Actor 管家會(huì)先向 用戶A Actor 發(fā)送扣款 100 元的信息疹启,接受到扣款成功消息后再發(fā)送消息給用戶B Actor古程,發(fā)送讓其增加 100 元的消息蔼卡。
一切看起來都很美好是吧,但這里面有一個(gè)問題挣磨,那就是在用戶A Actor 扣款期間雇逞,用戶B Actor 是不受限制的,此時(shí)對(duì)用戶B Actor 進(jìn)行操作是合法的茁裙!針對(duì)這種情況單純的Actor模型就顯得比較乏力了塘砸,需要加入其他機(jī)制以保證一致性。
看到這你就明白了晤锥,Actor 模型并非萬能的掉蔬,它有一定的缺點(diǎn)廊宪。那就是針對(duì)一致性要求比較強(qiáng)的場(chǎng)景比較乏力。
三. 為什么會(huì)出現(xiàn) Actor 模型
接下來我們來聊聊為什么會(huì)有 Actor 模型這種并發(fā)編程模型出現(xiàn)女轿。
我們需要先說說并發(fā)性中的一致性和隔離性箭启。
一致性即讓數(shù)據(jù)保持一致,比如銀行轉(zhuǎn)賬例子中蛉迹,用戶A 轉(zhuǎn)給 用戶B 100塊錢傅寡,沒有其他干擾的情況下,轉(zhuǎn)賬完成時(shí)北救。用戶A 的賬戶必然減少 100 元荐操,用戶B 的賬戶必然增加100 元,這就滿足了一致性珍策。不能說用戶A 減少50 或用戶B 增加了 200托启。
隔離性可以理解為犧牲一部分的一致性需求,而獲得性能的提高膛壹。打個(gè)比方驾中,在完全一致的情況下,任務(wù)都是串行的模聋,這時(shí)候也就不存在隔離性了肩民。
明白這些之后,你就直到為什么會(huì)有 Actor 模型了链方。
傳統(tǒng)并發(fā)模式持痰,共享內(nèi)存是傾向于強(qiáng)一致性弱隔離性的。比如悲觀鎖/同步的方式祟蚀,其實(shí)就是使用強(qiáng)一致性的方式控制并發(fā)工窍。而Actor 模型天然是強(qiáng)隔離性且弱一致性,所以 Actor 模型在并發(fā)中有良好的性能前酿,且易于控制和管理患雏。
這樣你就明白 Actor 模型適合于什么樣的并發(fā)場(chǎng)景了,當(dāng)對(duì)一致性需求不是很高的情況下且對(duì)性能需求較高時(shí)罢维,Actor 模型無疑是一個(gè)值得嘗試的方案淹仑。