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中的所有块默认是单线程的,这就意味着完成以上两步的TransfromBlockActionBlock都是以一个线程挨个处理消息数据 (这也是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并发模型到底哪个快?相关推荐

  1. Actor并发模型入门

    使用Scala,基于Akka的Actor并发模型. import akka.actor.Actor import akka.actor.Props import akka.actor.ActorSys ...

  2. 浅谈Actor并发模型

    目录 0x00    Actor出现的背景 0x01    Actor如何通过消息传递避免数据竞争? 0x02    Actor到底是什么? 0x03    Actor特性 0x031    容错 0 ...

  3. 共享内存生产者消费者模型

    转载于:https://www.cnblogs.com/kangbry/p/4077359.html

  4. 并发编程含义比较广泛,包含多线程编程、多进程编程及分布式程序等 目录 1. “共享内存系统”,消息传递系统”。 1 1.1. 共享模式 多进程 多线程 1 1.2. Actor消息模式 事件驱动 2

    并发编程含义比较广泛,包含多线程编程.多进程编程及分布式程序等 目录 1. "共享内存系统",消息传递系统". 1 1.1. 共享模式 多进程 多线程 1 1.2. Ac ...

  5. 访问时发生了共享冲突是什么意思_【CUDA 基础】5.1 CUDA共享内存概述

    Abstract: 本文为CUDA内存的概述,介绍共享内存的模型,分配,访问,配置,同步等内容Keywords: 模型,分配,访问,配置,同步 开篇废话 这里首先要进一步说明一下,前面我们在说缓存的时 ...

  6. 【Linux】进程间通信--systemV标准--共享内存

    文章目录 systemV 标准 共享内存通信原理 共享内存的理解 共享内存的创建--shmget函数 查看共享内存和释放共享内存方式 挂在共享内存--shmat函数 去挂在共享内存--shmdt函数 ...

  7. Linux进程间通信一 System V 共享内存简介与示例

    目录 1. System V共享内存简介 2. API介绍 2.0 key_t和标识符 2.1  创建system v共享内存 2.2 映射共享内存并使用 2.3 取消共享内存映射 2.4 控制共享内 ...

  8. linux篇【9】:进程间通信(共享内存)——<后序>

    目录 一.system V共享内存--先让不同的进程看到同一份资源 1.共享内存原理 监控共享内存脚本 2.创建/获取 共享内存接口-shmget函数(shared memory get) 3.参数k ...

  9. 并发模型之——共享内存模型(线程与锁)理论篇

    这里我们使用Java的线程与锁来解析共享内存模型:做过java开发并且了解线程安全问题的知道,要使某段代码是线程安全的那必须要满足两个条件:内存可见性.原子性: 内存可见性       在JVM规定多 ...

最新文章

  1. 解决问题 inner element must either be a resource reference or empty.
  2. 项目4---罗列并解释阿里云服务的存储产品
  3. 2013百度校园招聘-机器学习和数据挖掘工程师-笔试题
  4. 【手把手教学】基于Maven构建方式使用Mybatis generator自动生成
  5. MVC中controller有什么作用
  6. java错误页面_Java web 项目关于错误页面的处理
  7. 别再用代码开发了,整理了30套实用可视化大屏模板,无套路直接领
  8. ASP.NET2.0 分页控件 PagerPro.dll (1.1.0 最新)
  9. 几款好用又强力的数据恢复软件推荐
  10. 这五款简单又实用自媒体排版工具,你不来试试?
  11. 树莓派sd卡linux分区,树莓派安装了Kali系统的SD卡扩容问题(分区太小)解决办法...
  12. 论文解读——神经网络翻译中的注意力机制 以及 global / local attention
  13. 创建express项目及npm start报错解决办法
  14. c#拼图碎片形状_1-3拼图碎片
  15. Nessus访问报错(Corrupt Database A corrupt database has been detected which prevents Nessus from........)
  16. linux7重置密码操作,在CentOS 7/RHEL 7系统上重置root密码的方法
  17. 区块链中的“双花”问题
  18. 轻快步伐远不足以跟上轻快心情
  19. mac 上最好用的SSH终端FinalShell
  20. Apollo第五讲——Apollo定位模块

热门文章

  1. 字符串表达式求值 C#实现
  2. HDU 3966 Aragorn's Story (树链剖分+线段树)
  3. Zabbix3.0 安装Graphtree
  4. php扩展开发1--添加函数
  5. Linux内核笔记--内存管理之用户态进程内存分配
  6. DB2 SQL 递归实现多行合并
  7. Adobe Air 写文件如何换行
  8. ArcGis融合小多边形到相邻多边形
  9. 转载 一篇UI规范文件
  10. 主动给团队或用户安装Teams App