C# 高并发场景下 共享内存 Actor并发模型到底哪个快?
HI,前几天被.NET圈纪检委@懒得勤快问到
共享内存
和Actor
并发模型哪个速度更快。
前文传送门:《三分钟掌握共享内存 & Actor并发模型》
说实在,我内心10w头羊驼跑过.....
先说结论
1.首先两者对于并发的风格模型不一样。
共享内存利用多核CPU的优势,使用强一致的锁机制控制并发, 各种锁交织,稍不注意可能出现死锁,更适合熟手。
Actor模型易于控制和管理,以消息触发、流水线挨个处理,天然分布式,思路清晰。
2.真要说性能,求100_000 以内的素数的个数]场景
& 电脑8c 16g的配置
•2.1 理论上如果以默认的Actor并发模型来做这个事情,共享内存模型是优于Actor模型的;•2.2 上文中我对于Actor做了多线程优化,Actor模型性能慢慢追上来了。
下面请听我唠嗑。
默认Actor模型
计算[100_000内素数的个数], 分为两步:
(1) 迭代判断当前数字是不是素数
(2) 如果是素数,执行sum++
完成以上两步,共享内存模型均能充分利用CPU多核心。
Actor模型:与TPL中的原语不同,TPL Datflow中的所有块默认是单线程的,这就意味着完成以上两步的TransfromBlock
和ActionBlock
都是以一个线程挨个处理消息数据 (这也是Dataflow的设计初衷,形成清晰单纯的流水线)。
猜测此时:共享内存相比默认的Actor模型更具优势。
使用NUnit做单元测试,数据量从小到大: 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]任一数字整除,就不是质数f = false;}if (f == true){Interlocked.Increment(ref sum);// 共享了sum对象,“++”就是调用sum对象的成员方法}});Console.WriteLine($"1-{num}内质数的个数是{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]任一数字整除,就不是质数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);// 准备从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(); // 通知头部,不再投递了; 会将信息传递到下游。actionBlock.Completion.Wait(); // 等待尾部执行完Console.WriteLine($"1-{num} Prime number include {sum}");}catch (Exception ex){Console.WriteLine($"1-{num} cause exception.",ex);} }}
}
测试结果如下:
测试结果印证我说的结论2.1
优化后的Actor模型
那后面我对Actor做了什么优化呢? 能产生下图的2.2结论。
请重新回看《三分钟掌握共享内存 & Actor并发模型TransfromBlock 块的细节:
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]任一数字整除,就不是质数f = false;}return f;}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism=50, EnsureOrdered = false }); // 这里开启多线程并发
上面说到默认的Actor是以单线程处理输入的消息,此次我们对这个TransfromBlock 块设置了MaxDegreeOfParallelism
参数,
这个参数能在Actor中开启多线程并发执行,但是这里面就不能有共享变量(否则你又得加锁),恰好我们完成 (1) 迭代判断当前数字是不是素数
这一步并不依赖共享对象,所以这(1)步开启多线程以后性能与共享内存模型基本没差别。
那为什么总体性能慢慢超过共享内存?
这是因为执行第二步(2) 如果是素数,执行sum++
, 共享内存要加/解锁,线程切换; 而Actor单线程挨个处理, 总体上Actor就略胜共享内存模型了。
这里再次强调,Actor模型执行第二步
(2) 如果是素数,执行sum++
,不可开启MaxDegreeOfParallelism
,因为依赖了共享变量sum
结束语
That's All, 感谢.NET圈纪检委@懒得勤快促使我重温了单元测试的写法 & 深度分析Actor模型风格。
请大家仔细对比结论和上图,脱离场景和硬件环境谈性能就是耍流氓,理解不同并发模型的风格和能力是关键, 针对场景和未来的拓展性、可维护性、可操作性做技术选型 。
本文内容和制图均为原创,文章永久更新地址请参阅左下角原文,如对您有所帮助,请一键三连,方便的话置一个星标 ~。。~。
专题相关 一网打尽
三分钟掌握共享内存 & Actor并发模型
你管这叫"线程安全"?
.Net线程同步技术解读
Redis分布式锁抽丝剥茧
看过这么多爆文,依旧走不好异步编程这条路?
TPL Dataflow组件应对高并发,低延迟要求
如何利用.NETCore向Azure EventHubs准实时批量发送数据?
难缠的布隆过滤器,这次终于通透了
扫码关注我们
不会让您失望的。
C# 高并发场景下 共享内存 Actor并发模型到底哪个快?相关推荐
- 共享内存 Actor并发模型到底哪个快?
HI,前几天被.NET圈纪检委@懒得勤快问到共享内存和Actor并发模型哪个速度更快. 前文传送门:<三分钟掌握共享内存 & Actor并发模型> 说实在,我内心10w头羊驼跑过. ...
- 高并发场景下数据库的常见问题及解决方案
一.分库分表 (1)为什么要分库分表 随着系统访问量的增加,QPS越来越高,数据库磁盘容量不断增加,一般数据库服务器的QPS在800-1200的时候性能最佳,当超过2000的时候sql就会变得很慢并且 ...
- 高并发场景下,到底先更新缓存还是先更新数据库?
在大型系统中,为了减少数据库压力通常会引入缓存机制,一旦引入缓存又很容易造成缓存和数据库数据不一致,导致用户看到的是旧数据. 为了减少数据不一致的情况,更新缓存和数据库的机制显得尤为重要,接下来带领大 ...
- 读数据库遇到空就进行不下去_如何解决高并发场景下缓存+数据库双写不一致问题?...
推荐阅读: 一只Tom猫:手撕分布式技术:限流.通讯.缓存,全部一锅端走送给你!zhuanlan.zhihu.com 一只Tom猫:MySQL复习:20道常见面试题(含答案)+21条MySQL性能调 ...
- 华为云:如何解除数据库高并发场景下的达摩克利斯之剑?
5月10-12日,第九届中国数据库技术大会(DTCC 2018)如约而至.大会邀请了百余位行业专家,就数据库.大数据等热点技术话题进行分享.其中,华为云数据库首席架构师 带来的主题演讲<MySQ ...
- java currenttimemillis 效率_高并发场景下System.currentTimeMillis()的性能问题的优化
前言 System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我也不知道,不过听说在100倍左右),然而该方法又是一个常用方法,有时不得不使用,比如生 ...
- 高并发场景下backlog详解
本文详解高并发场景下backlog的配置和作用 环境介绍: PHP 7.3.57 +nginx/1.16.0 +Linux CentOS Linux release 8.1.1911 (Core) b ...
- 高并发场景下缓存的常见问题
作者介绍: 丁浪,非著名架构师.关注高并发.高可用的架构设计,对系统服务化.分库分表.性能调优等方面有深入研究和丰富实践经验.热衷于技术研究和分享. 声明:版权归丁浪作者本人所有,转载请联系作者本人 ...
- 本地缓存需要高时效性怎么办_缓存在高并发场景下的常见问题
缓存一致性问题 当数据时效性要求很高时,需要保证缓存中的数据与数据库中的保持一致,而且需要保证缓存节点和副本中的数据也保持一致,不能出现差异现象.这就比较依赖缓存的过期和更新策略.一般会在数据发生更改 ...
- 分布式锁和mysql事物扣库存_这个是真的厉害,高并发场景下的订单和库存处理方案,讲的很详细了!...
前言 之前一直有小伙伴私信我问我高并发场景下的订单和库存处理方案,我最近也是因为加班的原因比较忙,就一直没来得及回复.今天好不容易闲了下来想了想不如写篇文章把这些都列出来的,让大家都能学习到,说一千道 ...
最新文章
- python培训班 北京-北京python培训班哪家好
- 计算机里的游戏可以找回吗,找回电脑游戏作文
- 《Java 核心技术卷1 第10版》学习笔记------ 类之间的关系
- C++11新特性,利用std::chrono精简传统获取系统时间的方法
- hdu3526(最小费用流)
- char的测试和含义
- python两个字典合并、相同key值保留_Python两个字典key相同的值组成新字典?
- SKlearn——逻辑斯蒂回归(LR)参数设置
- 机器学习 - [源码实现决策树小专题]决策树中子数据集的划分(不允许调用sklearn等库的源代码实现)
- c调用python函数_python - Linux C调用Python 函数
- 8音度dsp调音教程_以速腾为例,对比加高品质DSP功放前后音响效果
- STM32ADC模拟/数字转换详解
- 推荐个汇编语言编译器 XP系统
- 摄氏度与华氏度之间的转换
- 微信小程序项目-uniapp黑马优购
- 关于二重积分,三重积分的理解
- 物联网环境监测数据中心-物联网项目开发
- 读书笔记:《黎明之街》
- Python模块configparser:加载配置文件config.ini
- WPF学习笔记——没有前途的WPF
热门文章
- xfs文件系统误删除文件恢复(testdisk工具)
- 台式计算机搜索不到无线信号,win7电脑搜不到无线信号怎么办_win7找不到无线网络怎么解决-win7之家...
- Pytorch-IMDB电影评论情感分析
- Microsoft Store打不开解决办法
- 修改手机上网服务器,怎么给手机修改dns上网地址
- 【前端三剑客二】CSS手术刀剖析第一篇
- Facebook 上传小游戏流程
- 华为联运游戏审核驳回:在未安装或需更新HMS Core的手机上,提示安装,点击取消后,游戏卡屏(集成的6.1.0.301版本游戏SDK)
- “21 天好习惯”第一期-2 2021牛客暑期多校训练营10 F、Train Wreck
- android移动端设计规范,干货|超全面的移动端UI 设计规范整理汇总(下)