并发模型值Actor和CSP

并发模型值Actor和CSP

一 传统并发和基于消息传递的并发

在多核CPU机器下,为了充分利用计算机的资源,我们需要进行并发编程

1.1 传统并发模型

多线程编程,就是传统的并发编程模式

传统的多线程编程,使用的是ShreadMemory(共享内存)的方式,来实现的

有并发的地方就有竞争,传统多线程的并发模式使用lock(锁),condition (条件变量)等同步原语来强制规定了进程的执行顺序,而这些同步原语本质上都是在各个线程中使用了锁来来实现

除了基于shared memory(共享内存)以外,还有什么其他的并发模型吗?

答案是有的,就是基于消息的并发模型

1.2 基于消息的并发模型

基于消息传递(Message Passing)的并发模型CSPActor

这两种模型很像,但还是有一些不同的地方

Actor模型:在Actor模型中,主角是Actor,类似一种workerActor彼此之间直接发送消息,不需要经过什么中介,消息是异步发送和处理的

在这里插入图片描述

CSP模型:CSP``模型中,worker之间不直接彼此联系,而是通过不同channel进行消息发布和侦听。消息的发送者和接收者之间通过Channel松耦合,发送者不知道自己消息被哪个接收者消费了,接收者也不知道是哪个发送者发送的消息

在这里插入图片描述

CSP介绍

CSP的是Communicating Sequential Processes (CSP)的缩写,翻译成中文是顺序通信进程,简称CSP

CSP的核心思想是多个线程之间通过Channel来通信,对应到golang中的chan结构,对应到Python中是Queue

Go语言的CSP模型是由协程Goroutine与通道Channel实现:

  • Go协程goroutine: 是一种轻量线程,它不是操作系统的线程,而是将一个操作系统线程分段使用,通过调度器实现协作式调度。是一种绿色线程,微线程,它与Coroutine协程也有区别,能够在发现堵塞后启动新的微线程。
  • 通道channel: 类似UnixPipe,用于协程之间通讯和同步。协程之间虽然解耦,但是它们和Channel有着耦合

三 Actor介绍

Actor模式有一点类似面向对象模型,世界上所有的东西都被命名为Actor。
单个Actor会拥有一些状态,比如为名字是book的Actor可能被描述为:

name : 西游记
author : 吴承恩
price : 99

到此为止好像和对象object没有什么不同,但是Actor不会给外界提供任何的行为接口.
比如book.getPrice()这是很自然的面向对象的写法,在Actor是不被允许的。
每一个Actor的属性绝不对外暴露,想和外界进行通信必须发送message,所以每个Actor自身都有一个邮箱(MailBox)

Actor模型描述了一组为了避免并发编程的常见问题的公理:

  1. 所有Actor状态是Actor本地的,外部无法访问。
  2. Actor必须只有通过消息传递进行通信。
  3. 一个Actor可以响应消息:推出新Actor,改变其内部状态,或将消息发送到一个或多个其他参与者。
  4. Actor可能会堵塞自己,但Actor不应该堵塞它运行的线程。

CSPActor的区别

Actor模型和CSP区别图如下:

在这里插入图片描述

Actor之间直接通讯,而CSP是通过Channel通讯,在耦合度上两者是有区别的,后者更加松耦合。

4.1 主要的不同点

关于消息发送方和接收方

Actor:注重的处理单元,也就是Actor,而不是消息传送方式。发送消息时,都需要知道对方是谁。

这里的“都需要知道对方是谁”的意思,当ActorX要给ActorY发消息时,必须明确知道ActorY的地址。ActorY接收到消息时,就能够知道消息发送者(ActorX)的地址。返回消息给发送者时,只需要按发送者的地址往回传消息就行。

CSP:注重的是消息传送方式(channel),不关心发送的人和接收的人是谁。

channel写消息的人,不知道消息的接收者是谁;读消息的人,也不知道消息的写入者是谁。

两者比较看来,CSP把发送方和接收方给解耦了,但这种解耦带的好处是什么呢?

消息传输方式

Actor:每一对Actor之间,都有一个“MailBox”来进行收发消息。消息的收发是异步的。
CSP:使用定义的 channel 进行收发消息。消息的收发是同步的(也可以做成异步的,但是一个有限异步)

Actor 模式消息传输,只有一个通道(MailBox),所以无论什么“类型”的消息都可能发过来,所以要做好模式配置。而 CSP 中的通道(channel)类型是定好的,而且两个对象可以可以使用多个通道传输消息。(CSP 把通信给细化了,让你在通信时有多种选择,例如:用一个 channel 传一类数据,用另一个 channel 传另一类数据)

这就和MQ的机制有点像了。在通过MQ传输消息时有两种选择:

选择把这个消息发送到哪个 Exchange(类似 channel)里,对于不同的 Exchange 可以有不同的处理程序。
还可以把数据发送到一个 Exchange 里,然后设置分发规则,选择不同的处理程序。

4.2 从写程序的角度来看,不同点

要做【关于取得RSS文章的单词数】这样的程序

CSP

步骤1:定义几个channel,保存不同处理的之间的数据:
1 新文章ch
2 文章内容ch
3 单词数ch

步骤2:然后写相应的处理程序:
1 新文章URL处理(把得取的新文章的URL,写入“新文章ch”)
2 新文章内容处理(把新文章内容读取下来,写入“文章内容ch”)
3 单词数统计(对文章内容进行单词个数统计,写入“单词数ch”)
4 文章单词数累加(读取“单词数ch”,把各个文章单词数进行累加)

步骤3:在主程序中,定义上面的几个channel,再调用几个处理程序,并把channel当成参数传给处理程序

Actor

步骤1:定义控制Actor,控制程序流程,功能如下:
1 当收到指令是“新文章URL处理”的话,调用“新文章URL处理”Actor,并把处理结果返回给调用者。
2 当收到指令是“新文章内容处理”的话,调用“新文章内容处理”Actor,并把处理结果返回给调用者。
3 当收到指令是“单词数统计”的话,调用“单词数统计”Actor,并把处理结果返回给调用者。
4 当收到指令是“文章单词数累加”的话,调用“文章单词数累加”Actor,并把处理结果返回给调用者。
(以上的每一个指令的执行,都可以做成并行的)

步骤2:定义指令相对应的处理程序。

步骤3:主程序,向“控制Actor”发指令,并把每次指令的结果当成参数,传给下一次的指令调用。

需求增加,在单词数统计时,去掉”of/to/and”这些单词,不同实现

CSP

主程序:
1 定义一个新的ch
2 并增加对内容过滤程序的调用。
3 传给“单词数统计”程序的ch,要修改成新定义的ch

子程序:
1 新加一个处理程序。

Actor

主程序:
1 增加对内容过滤Actor的调用
控制Actor:
1 增加一个新的内容过滤指令
子程序:
1 定义一个新的内容过滤Actor

4.3 总结

它们都是描述独立的流程通过消息传递进行通信
主要的区别在于:在CSP消息交换是同步的(即两个流程的执行"接触点"的,在此他们交换消息),而Actor模型是完全解耦的,可以在任意的时间将消息发送给任何未经证实的接受者。

由于Actor享有更大的相互独立,因为他可以根据自己的状态选择处理哪个传入消息。自主性更大些。

在Go语言中为了不堵塞流程,程序员必须检查不同的传入消息,以便预见确保正确的顺序。CSP好处是Channel不需要缓冲消息,而Actor理论上需要一个无限大小的邮箱作为消息缓冲

无论CSP或者Actor,他们都贯彻了一句话:

Don’t communicate by sharing memory; share memory by communicating.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值