并发编程模型
一、并行工作者模型
委派者(Delegator)将传入的作业分配给不同的worker;
每个worker完成整个任务;
workers并行运作在不同的线程上,甚至可能在不同的 CPU 上。
缺点:
a、处理共享资源复杂;
b、worker无状态,需每次重读数据,某些情况下影响性能;
c、任务顺序不确定。
二、事件驱动模型(流水线模型)
每个worker只负责作业中的部分工作;
当完成了自己的这部分工作时工作者会将作业转发给下一个工作者;
每个工作者在自己的线程中运行,并且不会和其他工作者共享状态,有时也被成为无共享并行模型。
通常使用非阻塞的 IO 来设计使用流水线并发模型的系统。
非阻塞 IO:一旦某个工作者开始一个 IO 操作的时候(比如读取文件或从网络连接中读取数据),该工作者不会一直等待 IO 操作的结束。IO 操作速度很慢,所以等待 IO 操作结束很浪费 CPU 时间。此时 CPU 可以做一些其他事情。当 IO 操作完成的时候,IO 操作的结果(比如读出的数据或者数据写完的状态)被传递给下一个工作者。
有了非阻塞 IO,就可以使用 IO 操作确定工作者之间的边界。工作者会尽可能多运行直到遇到并启动一个 IO 操作。然后交出作业的控制权。当 IO 操作完成的时候,在流水线上的下一个工作者继续进行操作,直到它也遇到并启动一个 IO 操作。
1、Actors模型(Akka)
Actor 模型中每个工作者被称为 actor,Actor 之间可以直接异步地发送和处理消息;
2、Channel模型
在 Channel 模型中,工作者之间不直接进行通信。相反,它们在不同的通道中发布自己的消息(事件)。其他工作者们可以在这些通道上监听消息,发送者无需知道谁在监听
事件驱动模型缺点:
作业的执行往往分布到多个工作者上,并因此分布到项目中的多个类上,这样导致在追踪某个作业到底被什么代码执行时变得困难;
代码编写难度大。
三、函数式并行
基本思想是采用函数调用实现程序。
函数可以看作是”代理人(agents)“或者”actor“,函数之间可以像事件驱动模型那样互相发送消息。某个函数调用另一个函数,这个过程类似于消息发送。
函数都是通过拷贝来传递参数的,所以除了接收函数外没有实体可以操作数据。可避免共享数据的竞态。同样也使得函数的执行类似于原子操作。每个函数调用的执行独立于任何其他函数的调用。
一旦每个函数调用都可以独立的执行,它们就可以分散在不同的 CPU 上执行了。这也就意味着能够在多处理器上并行的执行使用函数式实现的算法。