我开始学习Scala和函数式编程。我正在读这本书!编程scala:解决Java虚拟机上的多核复杂性“。在第一章我看到了事件驱动的并发和Actor模型这个词。在我继续阅读本书之前,我希望有一个关于事件驱动并发或Actor模型的想法。
什么是事件驱动的并发性,它与Actor模型有什么关系?
答案 0 :(得分:16)
事件驱动编程模型涉及注册在给定事件触发时要运行的代码。一个例子是,而不是调用从数据库返回一些数据的方法:
val user = db.getUser(1)
println(user.name)
您可以在数据准备就绪时注册要运行的回调:
db.getUser(1, u => println(u.name))
在第一个例子中,没有发生并发;当前线程将阻塞,直到db.getUser(1)
从数据库返回数据。在第二个示例中,db.getUser
将立即返回并继续执行程序中的下一个代码。与此同时,回调u => println(u.name)
将在未来的某个时刻执行。
有些人更喜欢第二种方法,因为它并不意味着内存饥饿线程不必要地等待缓慢的I / O返回。
Actor模型是一个如何使用事件驱动的概念来帮助程序员轻松编写并发程序的示例。
从超高级别开始,Actors是定义一系列事件驱动消息处理程序的对象,当Actor收到消息时会触发这些处理程序。在Akka中,Actor的每个实例都是单个Threaded,但是当这些Actors中的许多放在一起时,它们会创建一个并发的系统。
例如,Actor A
可以并行向Actor B
和C
发送消息。演员B
和C
可以将消息发送回演员A
。演员A
会有消息处理程序来接收这些消息,并按照需要运行。
要了解有关Actor模型的更多信息,我建议您阅读Akka文档。 真的写得很好:http://doc.akka.io/docs/akka/2.1.4/
在网络上还有很多关于事件驱动并发的好文档,我们比我在这里写的要详细得多。 http://berb.github.io/diploma-thesis/original/055_events.html
答案 1 :(得分:2)
Theon的回答提供了一个很好的现代概述。我想补充一些历史观点。
Tony Hoare和Robert Milner都开发了用于分析并发系统的数学代数(通信顺序进程,CSP和通信并发系统,CCS)。对于我们大多数人来说,这两个看起来都是沉重的数学,但实际应用相对简单。 CSP直接导致了Occam编程语言,其中Go是最新的例子。 CCS导致Pi演算和沟通频道的移动性结束,这是Go的一部分,并在过去十年左右被添加到Occam。
CSP简单地通过考虑自动实体('进程',v.lightweight之类的东西,如绿色线程)简单地通过事件交换进行交互来模拟并发性。传递事件的媒介是沿着渠道。进程可能必须处理多个输入或输出,并且它们通过选择首先准备好的事件来完成此操作。事件通常将数据从发送者传送到接收者。
CSP模型的一个主要特征是,只有当两者都准备就绪时,一对流程才能进行通信 - 实际上,这会导致通常所谓的“同步”通信。但是,实际的实现(Go,Occam,Akka)允许缓冲通道(Akka中的正常状态),因此锁定步骤事件交换通常实际上是解耦的。
总而言之,事件驱动的基于CSP的系统实际上是通过通道连接的进程的数据流网络。
除了CSP对事件驱动的解释外,还有其他人。一个重要的例子是“事件轮”方法,曾经很受欢迎,用于建模并发系统,同时实际上只有一个处理线程。这些系统通过将事件放入处理队列并在适当时候处理它们来处理事件,通常是通过回调。 Java Swing的事件处理引擎就是一个很好的例子。还有其他人,例如用于基于时间的模拟引擎。有人可能会认为Javascript / NodeJS模型也适合这个类别。
总而言之,事件轮是一种表达并发性但没有并行性的方法。
具有讽刺意味的是,我上面描述的两种方法都被描述为事件驱动,但它们在事件驱动中的含义在每种情况下都是不同的。在一种情况下,类似硬件的实体连接在一起;另一方面,几乎所有动作都是由回调执行的。 CSP方法声称可扩展,因为它完全可组合;它自然也擅长并行执行。如果有任何理由支持一个而不是另一个,那么可能就是这样。