共享内存 Actor并发模型到底哪个快?
HI,前幾天被.NET圈紀(jì)檢委@懶得勤快問到共享內(nèi)存和Actor并發(fā)模型哪個(gè)速度更快。
前文傳送門:《三分鐘掌握共享內(nèi)存 & Actor并發(fā)模型》
說實(shí)在,我內(nèi)心10w頭羊駝跑過.....
先說結(jié)論
1.首先兩者對于并發(fā)的風(fēng)格模型不一樣。
共享內(nèi)存利用多核CPU的優(yōu)勢,使用強(qiáng)一致的鎖機(jī)制控制并發(fā), 各種鎖交織,稍不注意可能出現(xiàn)死鎖,更適合熟手。
Actor模型易于控制和管理,以消息觸發(fā)、流水線挨個(gè)處理,天然分布式,思路清晰。
2.真要說性能,求100_000 以內(nèi)的素?cái)?shù)的個(gè)數(shù)]場景?&?電腦8c 16g的配置
?2.1 理論上如果以默認(rèn)的Actor并發(fā)模型來做這個(gè)事情,共享內(nèi)存模型是優(yōu)于Actor模型的;?2.2 上文中我對于Actor做了多線程優(yōu)化,Actor模型性能慢慢追上來了。
下面請聽我嘮嗑。
默認(rèn)Actor模型
計(jì)算[100_000內(nèi)素?cái)?shù)的個(gè)數(shù)], 分為兩步:
(1) 迭代判斷當(dāng)前數(shù)字是不是素?cái)?shù)
(2) 如果是素?cái)?shù),執(zhí)行sum++
完成以上兩步,共享內(nèi)存模型均能充分利用CPU多核心。
Actor模型:與TPL中的原語不同,TPL Datflow中的所有塊默認(rèn)是單線程的,這就意味著完成以上兩步的TransfromBlock和ActionBlock都是以一個(gè)線程挨個(gè)處理消息數(shù)據(jù)?(這也是Dataflow的設(shè)計(jì)初衷,形成清晰單純的流水線)。
猜測此時(shí):共享內(nèi)存相比默認(rèn)的Actor模型更具優(yōu)勢。
使用NUnit做單元測試,數(shù)據(jù)量從小到大: 10_000,50_000,100_000,200_000,300_000,500_000
using?NUnit.Framework; using?System; using?System.Threading.Tasks; using?System.Collections.Generic; using?System.Threading; using?System.Threading.Tasks.Dataflow;namespace?TestProject2 {public?class?Tests{[TestCase(10_000)][TestCase(50_000)][TestCase(100_000)][TestCase(200_000)][TestCase(300_000)][TestCase(500_000)]public?void?ShareMemory(int?num){var?sum?=?0;Parallel.For(1,?num?+?1,?(x,?state)?=>{var?f?=?true;if?(x?==?1)f?=?false;for?(int?i?=?2;?i?<=?x?/?2;?i++){if?(x?%?i?==?0)??//?被[2,x/2]任一數(shù)字整除,就不是質(zhì)數(shù)f?=?false;}if?(f?==?true){Interlocked.Increment(ref?sum);//?共享了sum對象,“++”就是調(diào)用sum對象的成員方法}});Console.WriteLine($"1-{num}內(nèi)質(zhì)數(shù)的個(gè)數(shù)是{sum}");}[TestCase(10_000)][TestCase(50_000)][TestCase(100_000)][TestCase(200_000)][TestCase(300_000)][TestCase(500_000)]public?async?Task?Actor(int?num){var?linkOptions?=?new?DataflowLinkOptions?{?PropagateCompletion?=?true?};var?bufferBlock?=?new?BufferBlock<int>();var?transfromBlock?=?new?TransformBlock<int,?bool>(x?=>{var?f?=?true;if?(x?==?1)f?=?false;for?(int?i?=?2;?i?<=?x?/?2;?i++){if?(x?%?i?==?0)??//?被[2,x/2]任一數(shù)字整除,就不是質(zhì)數(shù)f?=?false;}return?f;},?new?ExecutionDataflowBlockOptions?{?EnsureOrdered?=?false?});var?sum?=?0;var?actionBlock?=?new?ActionBlock<bool>(x?=>{if?(x?==?true)sum++;},?new?ExecutionDataflowBlockOptions?{??EnsureOrdered?=?false?});transfromBlock.LinkTo(actionBlock,?linkOptions);//?準(zhǔn)備從pipeline頭部開始投遞try{var?list?=?new?List<int>?{?};for?(int?i?=?1;?i?<=?num;?i++){var?b?=?await?transfromBlock.SendAsync(i);if?(b?==?false){list.Add(i);}}if?(list.Count?>?0){Console.WriteLine($"md,num?post?failure,num:{list.Count},post?again");//?再投一次foreach?(var?item?in?list){transfromBlock.Post(item);}}transfromBlock.Complete();??//?通知頭部,不再投遞了;?會(huì)將信息傳遞到下游。actionBlock.Completion.Wait();??//?等待尾部執(zhí)行完Console.WriteLine($"1-{num}?Prime?number?include?{sum}");}catch?(Exception?ex){Console.WriteLine($"1-{num}?cause?exception.",ex);}???}} }測試結(jié)果如下:
測試結(jié)果印證我說的結(jié)論2.1
優(yōu)化后的Actor模型
那后面我對Actor做了什么優(yōu)化呢?? 能產(chǎn)生下圖的2.2結(jié)論。
請重新回看《三分鐘掌握共享內(nèi)存 & Actor并發(fā)模型》 TransfromBlock 塊的細(xì)節(jié):
var?transfromBlock?=?new?TransformBlock<int,?bool>(x?=>{var?f?=?true;if?(x?==?1)f?=?false;for?(int?i?=?2;?i?<=?x?/?2;?i++){if?(x?%?i?==?0)??//?被[2,x/2]任一數(shù)字整除,就不是質(zhì)數(shù)f?=?false;}return?f;},?new?ExecutionDataflowBlockOptions?{?MaxDegreeOfParallelism=50,?EnsureOrdered?=?false?}); // 這里開啟多線程并發(fā)上面說到默認(rèn)的Actor是以單線程處理輸入的消息,此次我們對這個(gè)TransfromBlock 塊設(shè)置了MaxDegreeOfParallelism?參數(shù),
這個(gè)參數(shù)能在Actor中開啟多線程并發(fā)執(zhí)行,但是這里面就不能有共享變量(否則你又得加鎖),恰好我們完成?(1) 迭代判斷當(dāng)前數(shù)字是不是素?cái)?shù)這一步并不依賴共享對象,所以這(1)步開啟多線程以后性能與共享內(nèi)存模型基本沒差別。
那為什么總體性能慢慢超過共享內(nèi)存?
這是因?yàn)閳?zhí)行第二步(2) 如果是素?cái)?shù),執(zhí)行sum++, 共享內(nèi)存要加/解鎖,線程切換;?而Actor單線程挨個(gè)處理,?總體上Actor就略勝共享內(nèi)存模型了。
這里再次強(qiáng)調(diào),Actor模型執(zhí)行第二步(2) 如果是素?cái)?shù),執(zhí)行sum++,不可開啟MaxDegreeOfParallelism,因?yàn)橐蕾嚵斯蚕碜兞縮um
結(jié)束語
That's All, 感謝.NET圈紀(jì)檢委@懶得勤快促使我重溫了單元測試的寫法 & 深度分析Actor模型風(fēng)格。
請大家仔細(xì)對比結(jié)論和上圖,脫離場景和硬件環(huán)境談性能就是耍流氓,理解不同并發(fā)模型的風(fēng)格和能力是關(guān)鍵, 針對場景和未來的拓展性、可維護(hù)性、可操作性做技術(shù)選型 。
本文內(nèi)容和制圖均為原創(chuàng),文章永久更新地址請參閱左下角原文,如對您有所幫助,請一鍵三連,方便的話置一個(gè)星標(biāo) ~。。~。
專題相關(guān) 一網(wǎng)打盡
??三分鐘掌握共享內(nèi)存 & Actor并發(fā)模型
?你管這叫"線程安全"?
?.Net線程同步技術(shù)解讀
?Redis分布式鎖抽絲剝繭
?看過這么多爆文,依舊走不好異步編程這條路?
?TPL Dataflow組件應(yīng)對高并發(fā),低延遲要求
?如何利用.NETCore向Azure EventHubs準(zhǔn)實(shí)時(shí)批量發(fā)送數(shù)據(jù)?
?難纏的布隆過濾器,這次終于通透了
掃碼關(guān)注我們
不會(huì)讓您失望的。
總結(jié)
以上是生活随笔為你收集整理的共享内存 Actor并发模型到底哪个快?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [007] 详解 .NET 程序集
- 下一篇: 自定义EventSource(二)Pol