并发和并行之间的区别是什么?


当前回答

并发是并行的广义形式。例如,并行程序也可以称为并发程序,但反向不成立。

可以在单个处理器上并发执行(多个线程,由调度器或线程池管理)在单个处理器上无法并行执行,但在多个处理器上无法。(每个处理器一个进程)分布式计算也是一个相关的主题,它也可以被称为并发计算,但反过来却不是,就像并行一样。

有关详细信息,请阅读本研究论文并行编程的概念

其他回答

我认为在这个问题上有两种不同的观点导致了混淆:程序员的观点(并发/并行编程)与计算机/操作系统的观点(并行/并行执行)。

这里回答了计算机的观点。

程序员的观点:

并发编程:程序员编写代码时知道代码将由多个线程执行,无论出于何种原因。原因可能是:在等待I/O时更好地利用CPU,通过不同线程处理Web请求,通过在独立于主线程的线程中运行计算,运行周期性后台任务,使GUI做出响应。程序员必须应用互斥构造、锁定/解锁、等待条件/信号、处理死锁等。多个线程可以在单个处理器/内核上运行(从计算机的角度来看是并发的),也可以在多个内核上运行。

并行编程:程序员知道程序将在具有多个处理器/内核的计算机上运行,并希望利用多个内核。程序员将CPU密集型计算划分为多个子任务,在一个线程中运行每个子任务,一旦线程完成,其结果将合并为总结果(分而治之)。例如,将一些矩阵处理代码划分为并行处理矩阵部分的任务。每个核心将使用子任务执行一个线程(如果线程数大于内核数,则同时执行多个线程)。程序员也必须在这里应用并发的编程构造,但她也关注将任务划分为子任务并合并结果。例如,在Java中,程序员可以使用ParallelStreams来分割数据并自动合并结果。如果程序员知道程序将在单核处理器上执行,那么将CPU密集型任务拆分为多个线程是没有好处的。摘自Doug Leah的《Java并发编程:设计原则和模式》,1999年第2版,第343页:

并行程序专门设计为利用多个CPU来解决计算密集型问题。

在电子学中,串行和并行表示一种静态拓扑,决定电路的实际行为。当没有并发时,并行性是确定性的。

为了描述动态的、与时间相关的现象,我们使用了术语顺序和并发。例如,可以通过特定的任务序列(例如配方)获得特定的结果。当我们与某人交谈时,我们会产生一系列单词。然而,在现实中,许多其他过程在同一时刻发生,因此,与某一行动的实际结果一致。如果很多人在同一时间谈话,同时进行的谈话可能会干扰我们的顺序,但这种干扰的结果事先不知道。并发性引入了不确定性。

串行/并行和顺序/并行表征是正交的。数字通信就是一个例子。在串行适配器中,数字消息沿同一通信线路(例如,一根电线)临时(即顺序)分布。在并行适配器中,这也在并行通信线路(例如多条电线)上进行划分,然后在接收端进行重构。

让我们想象一个有9个孩子的游戏。如果我们将它们作为一条链处理,在开始时发送消息,在结束时接收消息,我们将进行串行通信。更多的单词组成了一系列的交流单元。

I like ice-cream so much. > X > X > X > X > X > X > X > X > X > ....

这是在串行基础结构上复制的顺序过程。

现在,让我们想象一下,把孩子们分成三组。我们把这个短语分成三部分,第一部分给左边的孩子,第二部分给中心线的孩子,等等。

I like ice-cream so much. > I like    > X > X > X > .... > ....
                          > ice-cream > X > X > X > ....
                          > so much   > X > X > X > ....

这是一个在并行基础结构上复制的顺序过程(尽管仍部分序列化)。

在这两种情况下,假设孩子之间有完美的沟通,结果会提前确定。

如果有其他人与您同时与第一个孩子交谈,那么我们将同时进行处理。我们不知道基础设施将考虑哪个过程,因此最终结果尚未提前确定。

将其视为服务队列,其中服务器只能服务队列中的第一个作业。

1个服务器,1个作业队列(有5个作业)->无并发,无并行性(只有一个作业被服务完成,队列中的下一个作业必须等待服务完成,并且没有其他服务器为其服务)

1个服务器,2个或多个不同的队列(每个队列有5个作业)->并发(因为服务器与队列中的所有第一个作业共享时间,相等或加权),仍然没有并行性,因为在任何时刻都有一个且唯一的作业在服务。

两个或多个服务器,一个队列->并行(两个作业同时完成),但没有并发(服务器不共享时间,第三个作业必须等待其中一个服务器完成)

2个或多个服务器,2个或更多不同的队列->并发性和并行性

换句话说,并发是共享完成作业的时间,它可能会占用相同的时间来完成作业,但至少它会提前开始。重要的是,可以将作业分割成更小的作业,这样可以进行交织。

并行性是通过更多并行运行的CPU、服务器、人员等实现的。

请记住,如果共享资源,则无法实现纯粹的并行性,但这正是并发性的最佳实际用途,它将承担另一项不需要该资源的工作。

我将提供一个与这里的一些流行答案有点冲突的答案。在我看来,并发是一个包含并行性的通用术语。并发适用于不同任务或工作单元在时间上重叠的任何情况。并行性更具体地适用于在同一物理时间评估/执行不同工作单元的情况。并行性存在的原因是加速了可以从多个物理计算资源中受益的软件。适用于并发的另一个主要概念是交互性。当从外部世界可以观察到任务的重叠时,互动性适用。交互性存在的原因是使软件能够响应真实世界的实体,如用户、网络对等体、硬件外围设备等。

并行性和交互性几乎完全独立于并发性。对于一个特定的项目,开发人员可能会关心其中之一,或者两者都不关心。它们往往会被混淆,尤其是因为线程这一令人厌恶的东西给了一个相当方便的原语来实现两者。

关于并行性的更多细节:

并行性存在于非常小的规模(例如处理器中的指令级并行性)、中等规模(例如多核处理器)和大型规模(例如高性能计算集群)。近年来,由于多核处理器的发展,软件开发人员暴露更多线程级并行性的压力越来越大。平行性与依赖性密切相关。依赖性限制了并行性的实现程度;如果一个任务依赖于另一个任务,则两个任务不能并行执行(忽略推测)。

程序员可以使用许多模式和框架来表达并行性:管道、任务池、数据结构上的聚合操作(“并行数组”)。

关于互动性的更多细节:

最基本和最常见的交互方式是使用事件(即事件循环和处理程序/回调)。对于简单的任务,事件是很好的。尝试使用事件执行更复杂的任务会导致堆栈撕裂(也称为回调地狱;也称为控制反转)。当你厌倦了事件时,你可以尝试更奇特的东西,比如生成器、协程(又称Async/Await)或合作线程。

出于对可靠软件的热爱,如果你想要的是交互性,请不要使用线程。

曲线几何非线性

我不喜欢Rob Pike的“并发不是并行;它更好”口号。并发既不比并行好,也不比并行差。并发性包括交互性,不能以更好/更差的方式与并行性进行比较。这就像说“控制流比数据更好”。

太好了,让我用一个场景来展示我的理解。假设有三个孩子:A,B,C。A和B说话,C听。对于A和B,它们是平行的:A: 我是A。B: 我是B。

但对于C来说,他的大脑必须同时进行听A和B的过程,这可能是:我是我A是B。