三分钟掌握共享内存 & Actor并发模型
吃点好的,很有必要。今天介绍常见的两种并发模型: 共享内存&Actor
共享内存
面向对象编程中,万物都是对象,数据+行为=对象;
多核时代,可并行多个线程,但是受限于资源对象,线程之间存在对共享内存的抢占/等待,实质是多线程调用对象的行为方法,这涉及#线程安全#线程同步#。

假如现在有一个任务,找100000以内的素数的个数,如果用共享内存的方法,代码如下:
可以看到,这些线程共享了sum变量,对sum做sum++操作时必须上锁。
using System;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
/// <summary>
/// 利用并行编程库Parallel,计算10000内素数的个数
/// </summary>
namespace Paralleler
{
class Program
{
static object syncObj = new object();
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
ShareMemory();
sw.Stop();
Console.WriteLine($"共享内存并发模型耗时:{sw.Elapsed}");
}
static void ShareMemory()
{
var sum = 0;
Parallel.For(1, 100000 + 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)
{
lock(syncObj)
{
sum++; // 共享了sum对象,“++”就是调用sum对象的成员方法
}
}
});
Console.WriteLine($"1-10000内质数的个数是{sum}");
}
}
}
共享内存更贴合"面向对象开发者的固定思维", 强调线程对于资源的掌控力。
Actor模型
Actor模型则认为一切皆是Actor,Actor模型内部的状态由自己的行为维护,外部线程不能直接调对象的行为,必须通过消息才能激发行为,也就是消息传递机制来代替共享内存模型对成员方法的调用, 这样保证Actor内部数据只能被自己修改, Actor模型= 数据+行为+消息。

还是找到10000内的素数,我们使用.NET TPL Dataflow来完成,代码如下:
每个Actor的产出物就是流转到下一个Actor的消息。
using System;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks.Dataflow;
using System.Diagnostics;
/// <summary>
/// 利用并行编程库Paralleler,计算10000内素数的个数
/// </summary>
namespace Paralleler
{
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Actor();
sw.Stop();
Console.WriteLine($"Actor并发模型耗时:{sw.Elapsed}");
}
static void Actor()
{
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 { MaxDegreeOfParallelism =50 });
var sum = 0;
var actionBlock = new ActionBlock<bool>(x=>
{
if (x == true)
sum++;
},new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 50 });
transfromBlock.LinkTo(actionBlock, linkOptions);
// 准备从pipeline头部开始投递
for (int i = 1; i <= 100000; i++)
{
transfromBlock.Post(i);
}
transfromBlock.Complete(); // 通知头部,不再投递了; 会将信息传递到下游。
actionBlock.Completion.Wait(); // 等待尾部执行完成
Console.WriteLine($"1-10000内质数的个数是{sum}");
}
}
}
Actor并发模型强调的是消息触发。
还不过瘾
共享内存模型: 其实是并行线程调用对象的成员方法,这里不可避免存在加锁/解锁, 需要开发者自行关注线程同步、线程安全。
Actor模型:以流水线管道的形式,各Actor独立处理各自专属业务,等待消息流入,我也很容易推断,每个Actor的实现过程:存在循环,不断处理新流入的消息。
var queue= new Queue(1000);
for{
if(queue.Dequeue() != null) {
// Done bussiness
}
Thread.Sleep(50ms);
}
所以Actor模型,开发者不用关注线程锁,同时,Actor模型解耦了调用关系,天然适合分布式场景。

总结陈词
- 何为“并发模型”,模型是达成某个方案的编程风格,共享内存/Actor并发模型说不上孰优孰劣,适用场景有偏向。
- 共享内存并发模型,更强调多线程对于资源的掌控力。
- 从概念上得知,Actor模型强调消息触发,更适合分布式场景,解耦了调用方和提供方(我这里演示的TPL Dataflow是进程内Actor模型)。
- Golang使用的
Channel是类Actor模型,使用Channel进一步解耦了调用的参与方,你都不用关注下游提供者是谁。
作为一名编程老兵,深知大家平时常用的是共享内存并发模型,开口闭口“多线程”,“锁”,
可能很多人并没有关注到Actor模型,微软进程内Actor TPL Dataflow香气侧漏,值得推荐。
多对比、多体验不同的编程风格,别有洞天。
三分钟掌握共享内存 & Actor并发模型的更多相关文章
- 共享内存 & Actor并发模型哪个更快?
HI,前几天被.NET圈纪检委@懒得勤快问到共享内存和Actor并发模型哪个速度更快. 前文传送门: 说实在,我内心10w头羊驼跑过...... 先说结论 首先两者对于并发的风格模型不一样. 共享内存 ...
- 三分钟掌控Actor模型和CSP模型
回顾一下前文<三分钟掌握共享内存模型和 Actor模型> Actor vs CSP模型 传统多线程的的共享内存(ShareMemory)模型使用lock,condition等同步原语来强行 ...
- Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()
下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...
- system v和posix的共享内存对比 & 共享内存位置
参考 http://www.startos.com/linux/tips/2011012822078.html 1)Linux和所有的UNIX操作系统都允许通过共享内存在应用程序之间共享存储空间. 2 ...
- Linux进程间通信——使用共享内存
一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存. ...
- IPC——共享内存
Linux进程间通信——使用共享内存 下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的 ...
- Linux 共享内存 详解
一.什么是共享内存区 共享内存区是最快的可用IPC形式.它允许多个不相关的进程去访问同一部分逻辑内存.如果需要在两个运行中的进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存区映射到 ...
- 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)
注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...
- Linux进程间通信——使用共享内存(转)
一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存. ...
随机推荐
- TVM性能评估分析(五)
TVM性能评估分析(五) Figure 3. A futher speed up with operator fusion Table 1. Performance issue of cuBLAS ...
- YOLOv3和YOLOv4长篇核心综述(下)
YOLOv3和YOLOv4长篇核心综述(下) 4.3.3 Neck创新 在目标检测领域,为了更好的提取融合特征,通常在Backbone和输出层,会插入一些层,这个部分称为Neck.相当于目标检测网络的 ...
- 使用js获取checkbox控件在GridView中的第几行
这次的知识点是如何使用js获取checkbox控件所在的是第几行!!! 我们可以使用 JavaScript 中自带的 rowIndex 和 cellIndex 来获取行和列的键值 (从0开始) 这两个 ...
- Python_Selenium之basepage 识别元素、浏览器操作、获取属性、鼠标事件、键盘事件、弹窗、切换frame、切换句柄等封装
#coding=gbkimport osimport timefrom selenium import webdriverfrom selenium.webdriver.common.by impor ...
- 技能篇:awk教程-linux命令
前言 AWK是一门解释型的编程语言.用于文本处理,它的名字来源于它的三位作者的姓氏:Alfred Aho, Peter Weinberger 和 Brian Kernighan awk 程序结构 运行 ...
- Java IO学习笔记六:NIO到多路复用
作者:Grey 原文地址:Java IO学习笔记六:NIO到多路复用 虽然NIO性能上比BIO要好,参考:Java IO学习笔记五:BIO到NIO 但是NIO也有问题,NIO服务端的示例代码中往往会包 ...
- ORA-01157:cannot identify/lock data file 6 - see DBWR trace file ORA-01110:data file 6:'/u01/app/oracle/oradata/PRDO2/sysaux02.dbf'
- 『心善渊』Selenium3.0基础 — 4、Selenium基础元素定位详解
目录 1.什么是元素定位 2.Selenium元素定位常用API (1)By_id 定位 (2)by_name 定位 (3)by_class_name 定位 (4)by_tag_name 定位 (5) ...
- Winform中只运行运行一个实例的方法
在Program类的main方法按如下代码编写即可 1 static void Main() 2 { 3 if (Process.GetProcessesByName(Process.GetCurre ...
- <题解>世界树
世界树<题解> 首先我们拿到这个题之后,能想到的一定是虚树,如果想不到的话,还是重新学一遍去吧 所以我们应该怎么做呢 虚树的板子不需要我再讲一遍了吧 所以对于这个题来说,怎么根据虚树上的节 ...