吃点好的,很有必要。今天介绍常见的两种并发模型: 共享内存&Actor

共享内存

面向对象编程中,万物都是对象,数据+行为=对象;

多核时代,可并行多个线程,但是受限于资源对象,线程之间存在对共享内存的抢占/等待,实质是多线程调用对象的行为方法,这涉及#线程安全#线程同步#。

假如现在有一个任务,找100000以内的素数的个数,如果用共享内存的方法,代码如下:

可以看到,这些线程共享了sum变量,对sumsum++操作时必须上锁。

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模型解耦了调用关系,天然适合分布式场景。

总结陈词

  1. 何为“并发模型”,模型是达成某个方案的编程风格,共享内存/Actor并发模型说不上孰优孰劣,适用场景有偏向。
  2. 共享内存并发模型,更强调多线程对于资源的掌控力。
  3. 从概念上得知,Actor模型强调消息触发,更适合分布式场景,解耦了调用方和提供方(我这里演示的TPL Dataflow是进程内Actor模型)。
  4. Golang使用的Channel类Actor模型,使用Channel进一步解耦了调用的参与方,你都不用关注下游提供者是谁。

作为一名编程老兵,深知大家平时常用的是共享内存并发模型,开口闭口“多线程”,“锁”,

可能很多人并没有关注到Actor模型,微软进程内Actor TPL Dataflow香气侧漏,值得推荐。

多对比、多体验不同的编程风格,别有洞天。

三分钟掌握共享内存 & Actor并发模型的更多相关文章

  1. 共享内存 & Actor并发模型哪个更快?

    HI,前几天被.NET圈纪检委@懒得勤快问到共享内存和Actor并发模型哪个速度更快. 前文传送门: 说实在,我内心10w头羊驼跑过...... 先说结论 首先两者对于并发的风格模型不一样. 共享内存 ...

  2. 三分钟掌控Actor模型和CSP模型

    回顾一下前文<三分钟掌握共享内存模型和 Actor模型> Actor vs CSP模型 传统多线程的的共享内存(ShareMemory)模型使用lock,condition等同步原语来强行 ...

  3. Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()

    下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...

  4. system v和posix的共享内存对比 & 共享内存位置

    参考 http://www.startos.com/linux/tips/2011012822078.html 1)Linux和所有的UNIX操作系统都允许通过共享内存在应用程序之间共享存储空间. 2 ...

  5. Linux进程间通信——使用共享内存

    一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存. ...

  6. IPC——共享内存

    Linux进程间通信——使用共享内存 下面将讲解进程间通信的另一种方式,使用共享内存.   一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的 ...

  7. Linux 共享内存 详解

    一.什么是共享内存区 共享内存区是最快的可用IPC形式.它允许多个不相关的进程去访问同一部分逻辑内存.如果需要在两个运行中的进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存区映射到 ...

  8. 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)

    注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...

  9. Linux进程间通信——使用共享内存(转)

    一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存. ...

随机推荐

  1. AI算子列表

    AI算子列表 概述 目前只有部分算子可在一个库中同时运行在MLU220和MLU270平台.也就是用户使用 ./build_cnplugin.sh --mlu270 命令编译生成的 libcnplugi ...

  2. CVPR2019:无人驾驶3D目标检测论文点评

    CVPR2019:无人驾驶3D目标检测论文点评 重读CVPR2019的文章,现在对以下文章进行点评. Stereo R-CNN based 3D Object Detection for Autono ...

  3. 激光雷达Lidar Architecture and Lidar Design(下)

    Considerations on Lidar Design 双基地还是单基地? 双轴还是同轴? 几何重叠 向上还是向下看? 关心分散还是只关心时间? 发射器和接收器的波长 是否可调? 发射器和接收器 ...

  4. 工作流中的流程追溯!详细解析Activiti框架中的历史组件

    Activit中的历史简介 历史: Activiti中的一个组件,可以捕获发生在进程执行中的信息并永久的保存.与运行时数据不同的是,当流程实例运行完成之后它还会存在于数据库中 历史实体对象有5个: H ...

  5. 这 7 个 Linux 命令,你是怎么来使用的?

    使用 Linux 系统的开发者,很多人都有自己喜欢的系统命令,下面这个几个命令令是我平常用的比较多的,分享一下. 我不会教科书般的罗列每个指令的详细用法,只是把日常开发过程中的一些场景下,经常使用的命 ...

  6. 微信小程序 -- 基于 movable-view 实现拖拽排序

    微信小程序 -- 基于 movable-view 实现拖拽排序 项目基于colorui样式组件 ColorUI组件库 (color-ui.com) 1.实现效果 2. 设计思路 movable-vie ...

  7. 【NX二次开发】Block UI 指定矢量

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  8. 基于webpack5封装的cli工具packx

    安装 用 npm / yarn 安装: $ npm install -D packx $ yarn add -D packx 特性 基于 webpack5 支持 less,sass 支持 spa/mp ...

  9. 一文带你了解 Redis 的发布与订阅的底层原理

    01.前言 发布订阅系统在我们日常的工作中经常会使用到,这种场景大部分情况我们都是使用消息队列的,常用的消息队列有 Kafka,RocketMQ,RabbitMQ,每一种消息队列都有其特性,关于 Ka ...

  10. JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇

    JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇 作为一个使用Java语言开发的程序员,我们都知道,要想运行Java程序至少需要安装JRE(安装JDK也没问题).我们也知道我们Java程序 ...