在Actor模型中,主角是Actor,类似一种worker,Actor彼此之间直接发送消息,不需要经过什么中介,消息是异步发送和处理的:
actor模型
Actor模型描述了一组为了避免并发编程的常见问题的公理:
1.所有Actor状态是Actor本地的,外部无法访问。
2.Actor必须只有通过消息传递进行通信。
3.一个Actor可以响应消息:推出新Actor,改变其内部状态,或将消息发送到一个或多个其他参与者。
4.Actor可能会堵塞自己,但Actor不应该堵塞它运行的线程。
Channel模型
Channel模型中,worker之间不直接彼此联系,而是通过不同channel进行消息发布和侦听。消息的发送者和接收者之间通过Channel松耦合,发送者不知道自己消息被哪个接收者消费了,接收者也不知道是哪个发送者发送的消息。
channel模型
Go语言的CSP模型是由协程Goroutine与通道Channel实现:
Go协程goroutine: 是一种轻量线程,它不是操作系统的线程,而是将一个操作系统线程分段使用,通过调度器实现协作式调度。是一种绿色线程,微线程,它与Coroutine协程也有区别,能够在发现堵塞后启动新的微线程。
通道channel: 类似Unix的Pipe,用于协程之间通讯和同步。协程之间虽然解耦,但是它们和Channel有着耦合。
Actor之间直接通讯,而CSP是通过Channel通讯,在耦合度上两者是有区别的,后者更加松耦合。
同时,它们都是描述独立的流程通过消息传递进行通信。主要的区别在于:在CSP消息交换是同步的(即两个流程的执行”接触点”的,在此他们交换消息),而Actor模型是完全解耦的,可以在任意的时间将消息发送给任何未经证实的接受者。由于Actor享有更大的相互独立,因为他可以根据自己的状态选择处理哪个传入消息。自主性更大些。
在Go语言中为了不堵塞流程,程序员必须检查不同的传入消息,以便预见确保正确的顺序。CSP好处是Channel不需要缓冲消息,而Actor理论上需要一个无限大小的邮箱作为消息缓冲。
1,关于消息发送方和接收方。
Actor:注重的处理单元,也就是Actor,而不是消息传送方式。发送消息时,都需要知道对方是谁。
这里的“都需要知道对方是谁”的意思,当ActorX要给ActorY发消息时,必须明确知道ActorY的地址。ActorY接收到消息时,就能够知道消息发送者(ActorX)的地址。返回消息给发送者时,只需要按发送者的地址往回传消息就行。
CSP:注重的是消息传送方式(channel),不关心发送的人和接收的人是谁。
向channel写消息的人,不知道消息的接收者是谁;读消息的人,也不知道消息的写入者是谁。
两者比较看来,CSP把发送方和接收方给解耦了,但这种解耦带的好处是什么呢?
2,消息传输方式
Actor:每一对Actor之间,都有一个“MailBox”来进行收发消息。消息的收发是异步的。
CSP:使用定义的 channel 进行收发消息。消息的收发是同步的(也可以做成异步的,但是一个有限异步)
看了《并发之痛 Thread,Goroutine,Actor》这篇文章的中,关于 Actor 和 CSP 不同点的说明,感觉有一点可能留意:
Actor 模式消息传输,只有一个通道(MailBox),所以无论什么“类型”的消息都可能发过来,所以要做好模式配置。而 CSP 中的通道(channel)类型是定好的,而且两个对象可以可以使用多个通道传输消息。(CSP 把通信给细化了,让你在通信时有多种选择,例如:用一个 channel 传一类数据,用另一个 channel 传另一类数据)
这就和MQ的机制有点像了。在通过MQ传输消息时有两种选择:
选择把这个消息发送到哪个 Exchange(类似 channel)里,对于不同的 Exchange 可以有不同的处理程序。
还可以把数据发送到一个 Exchange 里,然后设置分发规则,选择不同的处理程序。
二、Actors模型
传统的并发模型主要由两种实现的形式,一是同一个进程下,多个线程天然的共享内存,由程序对读写做同步控制(有锁或无锁). 二是多个进程通过进程间通讯或者内存映射实现数据的同步.
Actors模型更多的使用消息机制来实现并发,目标是让开发者不再考虑线程这种东西,每个Actor最多同时只能进行一样工作,Actor内部可以有自己的变量和数据.
Actors模型避免了由操作系统进行任务调度的问题,在操作系统进程之上,多个Actor可能运行在同一个进程(或线程)中.这就节省了大量的Context切换.
在Actors模型中,每个Actor都有一个专属的命名”邮箱”, 其他Actor可以随时选择一个Actor通过邮箱收发数据,对于“邮箱”的维护,通常是使用发布订阅的机制实现的,比如我们可以定义发布者是自己,订阅者可以是某个Socket接口,另外的消息总线或者直接是目标Actor.
目前akka库是比较流行的Actors编程模型实现,支持Scala和Java语言.
三、CSP模型
CSP(Communicating Sequential Process)模型提供一种多个进程公用的“管道(channel)”, 这个channel中存放的是一个个”任务”.
目前正流行的go语言中的goroutine就是参考的CSP模型,原始的CSP中channel里的任务都是立即执行的,而go语言为其增加了一个缓存,即任务可以先暂存起来,等待执行进程准备好了再逐个按顺序执行.
四、CSP和Actor的区别
CSP进程通常是同步的(即任务被推送进Channel就立即执行,如果任务执行的线程正忙,则发送者就暂时无法推送新任务),Actor进程通常是异步的(消息传递给Actor后并不一定马上执行).
CSP中的Channel通常是匿名的, 即任务放进Channel之后你并不需要知道是哪个Channel在执行任务,而Actor是有“身份”的,你可以明确的知道哪个Actor在执行任务.
在CSP中,我们只能通过Channel在任务间传递消息, 在Actor中我们可以直接从一个Actor往另一个Actor传输数据.
CSP中消息的交互是同步的,Actor中支持异步的消息交互.