淺談JAVA Actor模型的一致性與隔離性
一.Actor模型介紹
在單核 CPU 發(fā)展已經(jīng)達(dá)到一個(gè)瓶頸的今天,要增加硬件的速度更多的是增加 CPU 核的數(shù)目。而針對(duì)這種情況,要使我們的程序運(yùn)行效率提高,那么也應(yīng)該從并發(fā)方面入手。傳統(tǒng)的多線程方法又極其容易出現(xiàn) Bug 而難以維護(hù),不過(guò)別擔(dān)心,今天將要介紹另一種并發(fā)的模式能一定程度解決這些問(wèn)題,那就是 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)建其他 Actor。 向其他 Actor 發(fā)送消息。 修改自身狀態(tài)。需要注意的是,盡管許多 Actor 同時(shí)運(yùn)行,但是一個(gè)actor只能順序地處理消息。也就是說(shuō)其它 Actor 發(fā)送了三條消息給一個(gè) Actor ,這個(gè) Actor 只能一次處理一條。所以如果你要并行處理3條消息,你需要把這條消息發(fā)給3個(gè)actors。
下面這張圖展示了一個(gè)簡(jiǎn)單的 Actor 模型系統(tǒng):
了解了 Actor 模型的大概規(guī)則后,我們用兩個(gè)具體的例子來(lái)看看 Actor 模型的妙處以及不足吧。
二. 兩個(gè)例子
2.1 素?cái)?shù)計(jì)算
假設(shè)我們現(xiàn)在有一個(gè)任務(wù),需要找出100000以?xún)?nèi)素?cái)?shù)個(gè)數(shù),并且使用多線程的方式實(shí)現(xiàn)。
下圖展示了使用共享內(nèi)存的方式和以Actor模型的方式進(jìn)行并發(fā)執(zhí)行。
這里展示了兩種處理并發(fā)的不同思路,傳統(tǒng)的方式是通過(guò)鎖/同步的方式來(lái)實(shí)現(xiàn)并發(fā),每次同步獲取當(dāng)前值,并讓一個(gè)線程去判斷值是否為素?cái)?shù),是的話(huà)再通過(guò)同步的方式對(duì)計(jì)數(shù)器加1(這里的說(shuō)明只是作為提供思路用,這種方法自然有很大的優(yōu)化空間)。
而使用 Actor 模型則不一樣,它將這一過(guò)程拆分成幾個(gè)模塊,即拆分成幾個(gè) Actor 。每個(gè) Actor 負(fù)責(zé)不同的部分,通過(guò)消息傳遞的方式讓這幾個(gè) Actor 協(xié)同工作,并且其中涉及到主要計(jì)算的 Actor 可以有多個(gè),通過(guò)多個(gè) Actor 協(xié)同工作實(shí)現(xiàn)并發(fā)。
2.2 銀行轉(zhuǎn)賬
銀行轉(zhuǎn)賬的任務(wù)描述很簡(jiǎn)單,假設(shè)有兩個(gè)用戶(hù),現(xiàn)在用戶(hù)A向用戶(hù)B轉(zhuǎn)賬100元,這個(gè) Actor 模型該如何設(shè)計(jì)呢?
用戶(hù) A 和 用戶(hù) B 明顯是兩個(gè) Actor ,但我們同時(shí)還需要一個(gè)可以控制用戶(hù)A Actor 和用戶(hù)B Actor 的 Actor ,我們稱(chēng)之為 轉(zhuǎn)賬管家 Actor。那么流程圖如下。
可以看到,當(dāng)一個(gè)轉(zhuǎn)賬需求過(guò)來(lái)的時(shí)候,Actor 管家會(huì)先向 用戶(hù)A Actor 發(fā)送扣款 100 元的信息,接受到扣款成功消息后再發(fā)送消息給用戶(hù)B Actor,發(fā)送讓其增加 100 元的消息。
一切看起來(lái)都很美好是吧,但這里面有一個(gè)問(wèn)題,那就是在用戶(hù)A Actor 扣款期間,用戶(hù)B Actor 是不受限制的,此時(shí)對(duì)用戶(hù)B Actor 進(jìn)行操作是合法的!針對(duì)這種情況單純的Actor模型就顯得比較乏力了,需要加入其他機(jī)制以保證一致性。
看到這你就明白了,Actor 模型并非萬(wàn)能的,它有一定的缺點(diǎn)。那就是針對(duì)一致性要求比較強(qiáng)的場(chǎng)景比較乏力。
三. 為什么會(huì)出現(xiàn) Actor 模型
接下來(lái)我們來(lái)聊聊為什么會(huì)有 Actor 模型這種并發(fā)編程模型出現(xiàn)。
我們需要先說(shuō)說(shuō)并發(fā)性中的一致性和隔離性。
一致性即讓數(shù)據(jù)保持一致,比如銀行轉(zhuǎn)賬例子中,用戶(hù)A 轉(zhuǎn)給 用戶(hù)B 100塊錢(qián),沒(méi)有其他干擾的情況下,轉(zhuǎn)賬完成時(shí)。用戶(hù)A 的賬戶(hù)必然減少 100 元,用戶(hù)B 的賬戶(hù)必然增加100 元,這就滿(mǎn)足了一致性。不能說(shuō)用戶(hù)A 減少50 或用戶(hù)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 模型無(wú)疑是一個(gè)值得嘗試的方案。
以上就是淺談JAVA Actor模型的一致性與隔離性的詳細(xì)內(nèi)容,更多關(guān)于JAVA Actor模型的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. IntelliJ IDEA設(shè)置默認(rèn)瀏覽器的方法2. idea設(shè)置提示不區(qū)分大小寫(xiě)的方法3. HTTP協(xié)議常用的請(qǐng)求頭和響應(yīng)頭響應(yīng)詳解說(shuō)明(學(xué)習(xí))4. IntelliJ IDEA創(chuàng)建web項(xiàng)目的方法5. VMware中如何安裝Ubuntu6. docker容器調(diào)用yum報(bào)錯(cuò)的解決辦法7. .NET SkiaSharp 生成二維碼驗(yàn)證碼及指定區(qū)域截取方法實(shí)現(xiàn)8. CentOS郵件服務(wù)器搭建系列—— POP / IMAP 服務(wù)器的構(gòu)建( Dovecot )9. css代碼優(yōu)化的12個(gè)技巧10. django創(chuàng)建css文件夾的具體方法
