首页 > 其他 > 详细

Actor 模型 / CSP 模型 / 共享内存模型

时间:2020-12-04 09:04:47      阅读:35      评论:0      收藏:0      [点我收藏+]

 

Actor 模型 / CSP 模型 / 共享内存模型

CSP 模型 通信顺序进程,其实就是基于 channel 的消息通信,在 ROS 中,这种 channel 称作主题 topic

erlang 是 actor 的代表性语言,go 是 CSP 的代表性语言

还有几个没怎么看的答案,不过都差不多了,这个讲历史比较多,也比较透彻,很有用,需要再仔细看!

https://stackoverflow.com/questions/22621514/is-scalas-actors-similar-to-gos-coroutines/22622880?r=SearchResults#22622880

https://stackoverflow.com/questions/20171442/is-communicating-sequential-processes-csp-an-alternative-to-the-actor-model-in?r=SearchResults

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 非常像,真是有种他山逢知音的感觉。:)

参考:

  1. http://jolestar.com/parallel-programming-model-thread-goroutine-actor/
  2. https://www.zhihu.com/question/26192499

http://wudaijun.com/2017/05/go-vs-erlang/

Actor 模型 / CSP 模型 / 共享内存模型

原文:https://www.cnblogs.com/cx2016/p/14083636.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!