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


当前回答

并发:如果一个处理器解决了两个或多个问题。

并行性:如果一个问题由多个处理器解决。

其他回答

派克的“并发”概念是一个有意的设计和实现决策。具有并发能力的程序设计可能表现出行为上的“并行性”;这取决于运行时环境。

你不希望一个不是为并发而设计的程序表现出并行性。:-)但就相关因素(功耗、性能等)而言,这是一个净收益,您需要最大程度的并发设计,以便主机系统可以在可能的情况下并行执行。

派克的Go编程语言将这一点发挥到了极致:他的函数都是可以同时正确运行的线程,也就是说,如果系统有能力,调用函数总是会创建一个与调用者并行运行的线程。一个拥有数百甚至数千个线程的应用程序在他的世界中是非常普通的。(我不是围棋专家,这只是我的看法。)

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

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

关于并行性的更多细节:

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

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

关于互动性的更多细节:

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

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

曲线几何非线性

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

它们解决不同的问题。并发性解决了CPU资源稀缺和任务多的问题。因此,您可以通过代码创建线程或独立的执行路径,以便在稀缺资源上共享时间。直到最近,由于CPU的可用性,并发性一直是讨论的焦点。

并行性解决了找到足够的任务和适当的任务(可以正确分割的任务)并将它们分配到大量的CPU资源上的问题。当然,并行性一直都存在,但由于多核处理器非常便宜,所以它正走到最前沿。

在我看来,理解这两者最简单、最优雅的方式是这样的。并发允许交错执行,因此会产生并行的错觉。例如,这意味着并发系统可以在您用Word编写文档的同时运行Youtube视频。底层操作系统是一个并发系统,使这些任务能够交错执行。由于计算机执行指令的速度如此之快,这就给人一种同时做两件事的感觉。

平行性是指这样的事情实际上是平行的。在上面的示例中,您可能会发现视频处理代码在一个内核上执行,而Word应用程序在另一个内核中运行。注意,这意味着并发程序也可以并行!使用线程和进程构建应用程序,使程序能够利用底层硬件,并可能并行完成。

那为什么不让一切都平行呢?一个原因是因为并发是一种结构化程序的方式,是一种促进关注点分离的设计决策,而并行常常以性能的名义使用。另一个问题是,有些事情根本上无法完全并行完成。这方面的一个例子是在队列的后面添加两件事——不能同时插入这两件事。一定要有东西在前面,另一个在后面,否则你会把队伍弄得一团糟。虽然我们可以交错这种执行(因此我们得到了一个并发队列),但不能让它并行。

希望这有帮助!

同意:具有共享资源潜力的多个执行流

前任:两个线程竞争I/O端口。

视差:将问题分成多个相似的块。

前任:通过对文件的每一半运行两个进程来解析大文件。