是否存在演员模型不适合的并发设计?

Ziv*_*Ziv 10 concurrency multithreading design-patterns

我注意到我遇到的所有设计都可以使用actor模式进行多线程 - 将每个工作模块分成不同的actor并使用消息队列(对我来说是.NET ConcurrentQueue)来传递消息.还有哪些好的多线程模型?

baz*_*zza 13

我认为,通信顺序进程是一种比并发行动模型更好的并发模型.它解决了actor模型(和其他模型)的许多问题,例如死锁,活锁,饥饿.看看这个,更实用的是,这个.

主要区别如下.在actor模型中,异步发送消息.但是在CSP中,消息是同步发送的; 发送方无法发送,直到接收方准备接收为止.

这一个简单的限制使世界变得不同.如果你的设计有不正确的死锁,那么在演员模型中它可能会或可能不会发生(而且通常只有在向老板演示时才会发生......).但是在CSP中,总是会发生死锁,让您毫无疑问地认为您的设计不正确.好的,所以你仍然需要解决它但是没关系; 修复你知道的问题比试图彻底测试没有问题(你在演员模型中唯一的选择)要容易得多.

CSP的严格同步方法似乎会导致响应时间出现问题; 例如,有人担心GUI线程无法继续运行,因为它无法向繁忙的工作线程发送消息,而该线程没有达到"读取"的程度.您需要做的是确保工作负载分布在足够的线程中,以便他们都可以在可接受的时间段内返回等待新消息.CSP不会让你逃脱它.演员模型确实不会被欺骗; 你只是在构建未来的问题.

在.NET中,ConcurrentQueue不是CSP的正确原语,除非您在顶部分层同步机制.我也在TCP套接字上添加了严格的同步.事实上,我通常最终会编写某种抽象套接字和管道的库,这样就无法确定"进程"(因为它们在CSP用语中已知)是该机器上的线程还是整个其他进程在网络连接结束时的另一台机器上.尼斯 - scalabilty从一开始就内置.

我已经用CSP方式做了23年了,我不会做任何其他方式.用这种方式构建了一些拥有数千个线程的大型系统

== ==编辑

看来这个答案仍然引起了一些关注,所以我想我会加入它.对于Windows开发人员,任务并行库都有DataFlow名称空间.它必须单独下载.微软如此嘲笑它:"这种数据流模型通过为粗粒度数据流和流水线操作提供进程内消息传递来促进基于actor的编程." 优秀!它使用像BufferBlocks这样的类作为通信通道.重要的是BufferBlock具有BoundedCapacity属性,默认为Unbounded,适合Actor模型.将此值设置为1,您现在已将其转换为CSP样式的通信通道.


baz*_*zza 7

要添加到我的上一个,除了CSP之外还有其他各种多线程模型.这个维基百科页面列出了其他几个,如CCS,ACPLOTOS.阅读这些文章暗示了学术界漫游的深洞和黑暗的洞穴,等待扑向流浪软件开发者.

问题在于学术上的默默无闻通常意味着在实际可用的水平上完全缺乏工具和库.将经过验证的经过验证的学术研究转化为一套图书馆和工具需要付出很多努力.对于更广泛的软件社区来说,接受理论论文并将其转化为实际现实并没有什么真正的动力.

我喜欢CSP,因为基于select()或pselect()实现自己的CSP库实际上很简单.我现在已经做了好几次了(我必须学习代码重用),还有肯特大学的优秀人才为那些喜欢Java的人安排了JCSP.我不建议在Occam开发(尽管它仍然可能); 支持和可维护性将成为未来的问题.CSP可能是最容易进入的人,并且鉴于其良好的特性,这是非常值得的.


baz*_*zza 6

@JeremyFriesner

未来的问题

为了扩展我对"未来问题"的看法,我指的是在异步系统中,消息的发送者不知道接收者是否真正跟上需求.发件人不知道,因为它知道的是某些消息缓冲区已接受该消息.然后,当接收者愿意接受它时,下面的传输(例如tcp)继续进行推送消息的工作.

因此,当处于压力下时,系统可能无法按要求执行,因为消息传输将不可避免地具有吸收接收器尚未接受的消息的有限容量.发件人只有在问题已经开始发展之后才发现这一点,到那时为止做任何事都可能为时已晚.

测试当然可以揭示这个问题,但是你必须要小心,测试确实已经耗尽了传输的吸收消息的能力.快速全速爆炸可能是骗人的.

当然,一个同步系统会产生一个开销("你准备好了吗?","不,还没有","现在?","是的!","这时你就是这样")这不会发生在异步系统.因此,平均而言,异步系统将更高效,实际上可能具有更高的吞吐量等.这就是为什么世界上大多数系统实际上是异步的,而且系统并不总能达到原始系统的全部容量的原因.网络带宽/处理时间可能暗示.在我看来,当接近满容量时,异步系统往往不会优雅地限制.

在我的问题中,我总是幸运地拥有过多的带宽,我选择同步路线是出于成功的原因; 我并没有真正失去很多带宽,但我失去了很多风险,这很好.

从同步转换为异步

也许,但它可能没什么价值.在同步系统中,如果您已成功平衡线程之间的分工,则它仅按要求工作.也就是说,有足够的线程执行慢位,以便不会阻止快速位.弄错了,系统肯定不够快.

但是,在完成这项任务后,您就拥有了一个系统,其中每个组件都能够毫无延迟地向前发送消息,因为它发送的所有内容都已准备好并等待(因为您在平衡工作负载时的技能和判断).因此,如果您确实转换为异步消息传输,那么您所做的只是在传输这些消息时节省很少的时间.您没有进行更改,这会导致工作负载得到更快的处理.但是,如果节省带宽是目标,那么也许它值得.

当然,进行这种平衡可能是一件困难的事情,并且处理诸如HDD访问时间,网络等的可变性可能难以克服.我经常不得不实施"下一个可用的"工作负载共享方案.但实际上,我和你一起玩的信号处理系统基本上处理的是像OpenVPX的RapidIO这样的非常可靠的传输,你只需要处理数据(不处理数据库,磁盘等),以及数据速率非常高(1GByte/sec这些天是完全可行的,事实上我处理的数据率高达13年前;这是哈佛的工作).严格同步意味着您要么明确地跟上数据速率,要么绝对不是.对于异步,它更像是一个......

适合所有人的实时操作系统!

拥有实时操作系统也是一个必不可少的组件,而且现在它似乎是Linux的PREEMPT_RT补丁集,它为很多业内人士提供了工作.Redhat做了一个预包装旋转(RedHat MRG),但是对于免费的科学Linux来自CERN的好人们是好的和免费的!我强烈怀疑如果使用PREEMPT_RT,很多系统在容量限制附近会更加平稳地运行 - 它可以很好地平滑事物.