Actor 模型 / CSP模型 / 共享内存模型
CSP模型 通信顺序进程,其实就是基于channel的消息通信,在ROS中,这种channel称作主题topic
erlang是actor的代表性语言,go是CSP的代表性语言
还有几个没怎么看的答案,不过都差不多了,这个讲历史比较多,也比较透彻,很有用,需要再仔细看!
http://en.wikipedia.org/wiki/Communicating_sequential_processes#Comparison_with_the_Actor_Model
理解ACTOR和CSP模型,有python源码。
https://www.codercto.com/a/9890.html
Actor 模型与Object模型
Theron框架是一个基于Actor模型的并发编程的C++库。而Actor模型使得Theron框架可以直接有效的创建并行分布式的应用。Theron框架提供了很多轻量便携的函数接口API,可以使用在Linux,Windows,Mac,ARM和Matlab环境。
我们知道面向对象编程中使用的是Object模型,宣扬一切皆是对象,数据+行为=对象。而Actor模型则认为一切皆是Actor,Actor模型内部的状态由自己的行为维护,外部线程不能直接调用对象的行为,必须通过消息才能激发行为,也就是使用消息传递机制来代替Object模型的成员方法的调用,这样就保证Actor内部数据只能被自己修改。Actor模型=数据+行为+消息。
但是C++是一种面向对象的语言,所以最终还是通过类来封装这种actor的机制,多线程的实现也是依靠内存共享的多线程机制设计的,只不过这些事情Theron源码已经帮我们完成了,我们直接使用它给出的类接口即可。Theron框架的多线程基础支持pthreads,Windows threads,boost::thread和C++11 threads四种传统类型来构建。多说一嘴,因为Theron框架在C++中说到底还是通过类封装实现Actor模型的,自然我们直接通过类对象调用类中方法数据。但是为了保证Theron框架生态的完整性,并且真正体现actor模型的优越性,我们还是不要如此为好。
基于Object模型与Actor模型区别如图3所示。
(a)
(b)
图3 基于Object机制与基于Actor机制的比较
从图中可以看到,类A的对象成员方法调用类B的对象成员方法需要经过A::call调用B::called方法,然后等待B::called方法执行完成并且返回响应,最后A::call继续上次调用的地方后面执行下去。而在Actor模型中,Actor A先发送消息给Actor B,然后即刻就返回继续执行下面的程序,而Actor B中收到消息被唤醒和Actor A并行执行下去。
至此,Actor模型就可以看出这种消息机制的线程调用最大好处是非阻塞的,多个线程可以同时并发进行,无需等待被调用方法执行完成返回消息的响应。当然,看到此处大家或许跟我一样有一点困惑的地方,即万一我们后面的程序需要立即使用它返回的响应消息怎么办呢?其实这也算Actor存在的一点不足之处,需要我们在设计多线程前考虑你的程序到底适不适合这种机制,后面我们会再详细描述。
---------------------
作者:无鞋童鞋
来源:CSDN
原文:https://blog.csdn.net/FX677588/article/details/74359823
版权声明:本文为博主原创文章,转载请附上博文链接!
3.2 Actor模型与共享内存模型不同点
Actor这种独立并发的模型,与另一种共享内存模型完全相反。Actor之间通过消息传递方式进行合作,相互线程独立。随着多核时代和分布式系统的到来,共享内存模型其实不适合开发的。我们以酒店厨房做菜为例,如图4所示。
图4 Actor模型与共享内存模型的比喻图示
①、单线程编程,如图4(a)——犹如酒店只有一个厨师员工(一个线程),所有菜按点菜顺序与工序完成到底就行;
②、共享内存的多线程编程,如图4(b)——犹如酒店厨房是由洗菜工,刀工,掌勺,服务员等(每个人是一个线程),他们之间的确能通过合作能比一个厨师完成所有工序要快。我们需要考虑的是菜相当于是他们共享的资源,每次只能一个人在对其做处理,虽然有多道菜品,但是总会在穿插间存在等待。
③、Actor模型的多线程编程,如图4(c)——犹如酒店有多个厨师,分别是川菜师傅,鲁菜师傅,徽菜师傅等等,他们只要接到客人点菜的需求,整个人独自完成相对应菜系的工序,之间不管对方师傅要干嘛,如此多线程工作就大大增加了效率,并且不存在互相等待资源的情况,做好了自己发消息给服务员端菜即可。
这样我们就可以看出Actor模型异步消息传递来触发程序并行执行,虽然不如直接调用来的直接而方便,但是它可以让大量消息真正意义上同步执行。同时消息让Actor之间解耦,消息发出去之后执行成功与否,耗时多少等等只要没有消息传递回来,一切都不在与发送方有任何关联。这样也保证了,我们不需要在共享环境中与同步锁,互斥体等常用基础多线程元素打交道。
---------------------
作者:无鞋童鞋
来源:CSDN
原文:https://blog.csdn.net/FX677588/article/details/74359823
版权声明:本文为博主原创文章,转载请附上博文链接!
这篇文章讲解了如何使用netmq来实现个简单的actor,同时也讲解了actor model的基本概念,与共享内存模型的区别
https://github.com/zeromq/netmq/blob/master/docs/actor.md
actor模型与CSP模型
https://www.jdon.com/concurrent/actor-csp.html
卧槽,ROS的主题就是CSP模型中的CHANNEL!!!
Actor模型和CSP模型的区别
Akka/Erlang的actor模型与Go语言的协程Goroutine与通道Channel代表的CSP(Communicating Sequential Processes)模型有什么区别呢?
首先这两者都是并发模型的解决方案,我们看看Actor和Channel这两个方案的不同:
Actor模型
在Actor模型中,主角是Actor,类似一种worker,Actor彼此之间直接发送消息,不需要经过什么中介,消息是异步发送和处理的:
Actor模型描述了一组为了避免并发编程的常见问题的公理:
1.所有Actor状态是Actor本地的,外部无法访问。
2.Actor必须只有通过消息传递进行通信。
3.一个Actor可以响应消息:推出新Actor,改变其内部状态,或将消息发送到一个或多个其他参与者。
4.Actor可能会堵塞自己,但Actor不应该堵塞它运行的线程。
更多可见Actor模型专题
Channel模型
Channel模型中,worker之间不直接彼此联系,而是通过不同channel进行消息发布和侦听。消息的发送者和接收者之间通过Channel松耦合,发送者不知道自己消息被哪个接收者消费了,接收者也不知道是哪个发送者发送的消息。
Go语言的CSP模型是由协程Goroutine与通道Channel实现:
- Go协程goroutine: 是一种轻量线程,它不是操作系统的线程,而是将一个操作系统线程分段使用,通过调度器实现协作式调度。是一种绿色线程,微线程,它与Coroutine协程也有区别,能够在发现堵塞后启动新的微线程。
- 通道channel: 类似Unix的Pipe,用于协程之间通讯和同步。协程之间虽然解耦,但是它们和Channel有着耦合。
Actor模型和CSP区别
Actor模型和CSP区别图如下:
Actor之间直接通讯,而CSP是通过Channel通讯,在耦合度上两者是有区别的,后者更加松耦合。
同时,它们都是描述独立的流程通过消息传递进行通信。主要的区别在于:在CSP消息交换是同步的(即两个流程的执行"接触点"的,在此他们交换消息),而Actor模型是完全解耦的,可以在任意的时间将消息发送给任何未经证实的接受者。由于Actor享有更大的相互独立,因为他可以根据自己的状态选择处理哪个传入消息。自主性更大些。
在Go语言中为了不堵塞流程,程序员必须检查不同的传入消息,以便预见确保正确的顺序。CSP好处是Channel不需要缓冲消息,而Actor理论上需要一个无限大小的邮箱作为消息缓冲。
https://www.cnblogs.com/feng9exe/p/10482436.html
源于从Erlang到Go的一些思维碰撞,就像当初从C++到Erlang一样,整理下来记于此。
Actor
Actor模型,又叫参与者模型,其”一切皆参与者(actor)”的理念与面向对象编程的“一切皆是对象”类似,但是面向对象编程中对象的交互通常是顺序执行的(占用的是调用方的时间片,是否并发由调用方决定),而Actor模型中actor的交互是并行执行的(不占用调用方的时间片,是否并发由自己决定)。
在Actor模型中,actor执行体是第一类对象,每个actor都有自己的ID(类比人的身份证),可以被传递。actor的交互通过发送消息来完成,每个actor都有一个通信信箱(mailbox,本质上是FIFO消息队列),用于保存已经收到但尚未被处理的消息。actorA要向actorB发消息,只需持有actorB ID,发送的消息将被立即Push到actorB的消息信箱尾部,然后返回。因此Actor的通信原语是异步的。
从actor自身来说,它的行为模式可简化为:
- 发送消息给其它的actor
- 接收并处理消息,更新自己的状态
- 创建其它的actor
一个好的Actor模型实现的设计目标:
- 调度器: 实现actor的公平调度
- 容错性: 具备良好的容错性和完善错误处理机制
- 扩展性: 屏蔽actor通信细节,统一本地actor和远程actor的通信方式,进而提供分布式支持
- 热更新? (还没弄清楚热更新和Actor模型,函数式范式的关联性)
在Actor模型上,Erlang已经耕耘三十余载,以上提到的各个方面都有非常出色的表现,其OTP整合了在Actor模型上的最佳实践,是Actor模型的标杆。
CSP
顺序通信进程(Communicating sequential processes,CSP)和Actor模型一样,都由独立的,并发的执行实体(process)构成,执行实体间通过消息进行通信。但CSP模型并不关注实体本身,而关注发送消息使用的通道(channel),在CSP中,channel是第一类对象,process只管向channel写入或读取消息,并不知道也不关心channel的另一端是谁在处理。channel和process是解耦的,可以单独创建和读写,一个process可以读写(订阅)个channel,同样一个channel也可被多个process读写(订阅)。
对每个process来说:
- 从命名channel取出并处理消息
- 向命名channel写入消息
- 创建新的process
Go语言并没有完全实现CSP理论(参见知乎讨论),只提取了CSP的process和channel的概念为并发提供理论支持。目前Go已经是CSP的代表性语言。
CSP vs Actor
- 相同的宗旨:”不要通过共享内存来通信,而应该通过通信来共享内存”
- 两者都有独立的,并发执行的通信实体
- Actor第一类对象为执行实体(actor),CSP第一类对象为通信介质(channel)
- Actor中实体和通信介质是紧耦合的,一个Actor持有一个Mailbox,而CSP中process和channel是解耦的,没有从属关系。从这一层来说,CSP更加灵活
- Actor模型中actor是主体,mailbox是匿名的,CSP模型中channel是主体,process是匿名的。从这一层来说,由于Actor不关心通信介质,底层通信对应用层是透明的。因此在分布式和容错方面更有优势
Go vs Erlang
- 以上 CSP vs Actor
- 均实现了语言级的coroutine,在阻塞时能自动让出调度资源,在可执行时重新接受调度
- go的channel是有容量限制的,因此只能一定程度地异步(本质上仍然是同步的),erlang的mailbox是无限制的(也带来了消息队列膨胀的风险),并且erlang并不保证消息是否能到达和被正确处理(但保证消息顺序),是纯粹的异步语义,actor之间做到完全解耦,奠定其在分布式和容错方面的基础
- erlang/otp在actor上扩展了分布式(支持异质节点),热更和高容错,go在这些方面还有一段路要走(受限于channel,想要在语言级别支持分布式是比较困难的)
- go在消息流控上要做得更好,因为channel的两个特性: 有容量限制并独立于goroutine存在。前者可以控制消息流量并反馈消息处理进度,后者让goroutine本身有更高的处理灵活性。典型的应用场景是扇入扇出,Boss-Worker等。相比go,erlang进程总是被动低处理消息,如果要做流控,需要自己做消息进度反馈和队列控制,灵活性要差很多。另外一个例子就是erlang的receive操作需要遍历消息队列(参考),而如果用go做同步调用,通过单独的channel来做则更优雅高效
Actor in Go
在用Go写GS框架时,不自觉地会将goroutine封装为actor来使用:
- GS的执行实体(如玩家,公会)的逻辑具备强状态和功能聚合性,不易拆分,因此通常是一个实体一个goroutine
- 实体接收的逻辑消息具备弱优先级,高顺序性的特点,因此通常实体只会暴露一个Channel与其它实体交互(结合go的interface{}很容易统一channel类型),这个channel称为RPC channel,它就像这个goroutine的ID,几乎所有逻辑goroutine之间通过它进行交互
- 除此之外,实体还有一些特殊的channel,如定时器,外部命令等。实体goroutine对这些channel执行select操作,读出消息进行处理
- 加上goroutine的状态数据之后,此时的goroutine的行为与actor相似:接收消息(多个消息源),处理消息,更新状态数据,向其它goroutine发送消息(通过RPC channel)
到目前为止,goroutine和channel解耦的优势并未体现出来,我认为主要的原因仍然是GS执行实体的强状态性和对异步交互流程的顺序性导致的。
在研究这个问题的过程中,发现已经有人已经用go实现了Actor模型: https://github.com/AsynkronIT/protoactor-go。 支持分布式,甚至supervisor,整体思想和用法和erlang非常像,真是有种他山逢知音的感觉。:)
参考:
- http://jolestar.com/parallel-programming-model-thread-goroutine-actor/
- https://www.zhihu.com/question/26192499
http://wudaijun.com/2017/05/go-vs-erlang/
//--------------------------------------------------------------------------------------------- 合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下。 积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得,圣心备焉。故不积跬步,无以至千里;不积小流,无以成江海。骐骥一跃,不能十步;驽马十驾,功在不舍。锲而舍之,朽木不折;锲而不舍,金石可镂。蚓无爪牙之利,筋骨之强,上食埃土,下饮黄泉,用心一也。蟹六跪而二螯,非蛇鳝之穴无可寄托者,用心躁也。