共享内存 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准实时批量发送数据?
难缠的布隆过滤器,这次终于通透了
扫码关注我们
不会让您失望的。
共享内存 Actor并发模型到底哪个快?相关推荐
- Actor并发模型入门
使用Scala,基于Akka的Actor并发模型. import akka.actor.Actor import akka.actor.Props import akka.actor.ActorSys ...
- 浅谈Actor并发模型
目录 0x00 Actor出现的背景 0x01 Actor如何通过消息传递避免数据竞争? 0x02 Actor到底是什么? 0x03 Actor特性 0x031 容错 0 ...
- 共享内存生产者消费者模型
转载于:https://www.cnblogs.com/kangbry/p/4077359.html
- 并发编程含义比较广泛,包含多线程编程、多进程编程及分布式程序等 目录 1. “共享内存系统”,消息传递系统”。 1 1.1. 共享模式 多进程 多线程 1 1.2. Actor消息模式 事件驱动 2
并发编程含义比较广泛,包含多线程编程.多进程编程及分布式程序等 目录 1. "共享内存系统",消息传递系统". 1 1.1. 共享模式 多进程 多线程 1 1.2. Ac ...
- 访问时发生了共享冲突是什么意思_【CUDA 基础】5.1 CUDA共享内存概述
Abstract: 本文为CUDA内存的概述,介绍共享内存的模型,分配,访问,配置,同步等内容Keywords: 模型,分配,访问,配置,同步 开篇废话 这里首先要进一步说明一下,前面我们在说缓存的时 ...
- 【Linux】进程间通信--systemV标准--共享内存
文章目录 systemV 标准 共享内存通信原理 共享内存的理解 共享内存的创建--shmget函数 查看共享内存和释放共享内存方式 挂在共享内存--shmat函数 去挂在共享内存--shmdt函数 ...
- Linux进程间通信一 System V 共享内存简介与示例
目录 1. System V共享内存简介 2. API介绍 2.0 key_t和标识符 2.1 创建system v共享内存 2.2 映射共享内存并使用 2.3 取消共享内存映射 2.4 控制共享内 ...
- linux篇【9】:进程间通信(共享内存)——<后序>
目录 一.system V共享内存--先让不同的进程看到同一份资源 1.共享内存原理 监控共享内存脚本 2.创建/获取 共享内存接口-shmget函数(shared memory get) 3.参数k ...
- 并发模型之——共享内存模型(线程与锁)理论篇
这里我们使用Java的线程与锁来解析共享内存模型:做过java开发并且了解线程安全问题的知道,要使某段代码是线程安全的那必须要满足两个条件:内存可见性.原子性: 内存可见性 在JVM规定多 ...
最新文章
- 解决问题 inner element must either be a resource reference or empty.
- 项目4---罗列并解释阿里云服务的存储产品
- 2013百度校园招聘-机器学习和数据挖掘工程师-笔试题
- 【手把手教学】基于Maven构建方式使用Mybatis generator自动生成
- MVC中controller有什么作用
- java错误页面_Java web 项目关于错误页面的处理
- 别再用代码开发了,整理了30套实用可视化大屏模板,无套路直接领
- ASP.NET2.0 分页控件 PagerPro.dll (1.1.0 最新)
- 几款好用又强力的数据恢复软件推荐
- 这五款简单又实用自媒体排版工具,你不来试试?
- 树莓派sd卡linux分区,树莓派安装了Kali系统的SD卡扩容问题(分区太小)解决办法...
- 论文解读——神经网络翻译中的注意力机制 以及 global / local attention
- 创建express项目及npm start报错解决办法
- c#拼图碎片形状_1-3拼图碎片
- Nessus访问报错(Corrupt Database A corrupt database has been detected which prevents Nessus from........)
- linux7重置密码操作,在CentOS 7/RHEL 7系统上重置root密码的方法
- 区块链中的“双花”问题
- 轻快步伐远不足以跟上轻快心情
- mac 上最好用的SSH终端FinalShell
- Apollo第五讲——Apollo定位模块