并发和并行有什么区别?

1560

并发和并行有什么区别?


347
并发是两排顾客从同一个收银员处点单(排队轮流点单);并行是两排顾客从两个收银员处点单(每一排都有自己的收银员)。 - chharvey
13
我认为这应该是答案。简洁明了(如果去掉“简短回答”的话只有两行文字),直接表达,易于理解。做得好! - Mike Maxwell
4
记忆这个比喻的助记符:并发 == 同时的“顾客”;并行 == 同时的“支付”。 - chadoh
2
@chharvey的简短回答很好。我想再加一句话来更清楚地解释:“在这里,每个收银员代表您机器的一个处理核心,而顾客则是程序指令。” - Code True
2
我不明白为什么@chharvey的答案会被投票这么多次 - 它是错误的。并发是指同时发生的事情的概念。并行是实现这一点的一种机制(同时进行计算)。如果我依次进行多个API请求,然后等待它们完成,这是并发但不是并行。 - Guy
显示剩余8条评论
41个回答

1754

并发性是指两个或多个任务可以在重叠的时间段内启动、运行和完成。这并不一定意味着它们将同时运行于同一时刻。例如,在单核机器上进行多任务处理

并行性是指任务实际上在同一时间内运行,例如,在多核处理器上。


引用Sun 的多线程编程指南:

  • 并发性: 当至少有两个线程正在进展时存在的一种情况。此为更一般形式的并行性,可包括作为虚拟并行性形式的分时。

  • 并行性: 当至少有两个线程同时执行时出现的一种情况。


225
我喜欢这个答案,但或许我会进一步将并发特性描述为程序或系统的属性(而将并行描述为同时执行多个任务的运行时行为)。 - Adrian Mouat
32
我非常喜欢Adrian Mouat的评论。还可以参考这个优秀的解释:http://www.haskell.org/haskellwiki/Parallelism_vs._Concurrency - jberryman
11
@Raj:正确,单核处理器不支持并行处理(指多线程的情况)。 - RichieHindle
5
如果Sequential和Parallel都是一个枚举类型中的值,那么这个枚举类型的名称会是什么? - toddmo
20
为了达到这个目的,孙先生的引语可以重新表述为:
  • 并发:在给定的一段时间内,两个线程都在取得进展时存在的条件。
  • 并行:在特定的时间点,两个线程同时执行时出现的情况。
- Phillip
显示剩余12条评论

853

为什么存在混淆

混淆之所以存在,是因为这两个词的字典意义几乎相同:

  • Concurrent(并发):同时存在、发生或完成(dictionary.com)
  • Parallel(并行):非常相似,通常同时发生(merriam webster)。

然而,在计算机科学和编程中使用它们的方式却有很大的不同。以下是我的解释:

  • Concurrency(并发性):可中断性
  • Parallelism(并行性):独立性

那么我上面的定义是什么意思呢?

我将通过一个现实世界的类比来澄清。假设你需要在一天内完成两个非常重要的任务:

  1. 办理护照
  2. 完成演示文稿

现在,问题是任务1需要你去一个极其官僚的政府办公室,而你必须排队等待4小时才能获得你的护照。与此同时,任务2是你的公司要求完成的,是一项关键任务。两项任务都必须在特定的日期完成。

情况1:顺序执行

通常,你会驾车去办理护照,需要2个小时的时间,在排队等候4个小时后,完成任务后又需要两个小时的车程回家,在家里再工作5个小时完成演示文稿。

情况2:并发执行

但是你聪明地提前计划了。你带着笔记本电脑去排队等待,并在等待期间开始编写演示文稿。这样,一旦你回到家,你只需要额外工作1个小时而不是5个小时。

在这种情况下,你完成了两项任务,只是分别完成它们的一部分。你打断了护照任务,在等待排队时开始工作演示文稿。当轮到你的号码时,你打断了演示文稿任务并切换到护照任务。节省的时间主要是由于两个任务的可中断性。

我认为,并发可以被理解为ACID中的“隔离”属性。如果可以在每个子事务中以任何交错的方式执行并且最终结果与按顺序执行两个任务的结果相同,则认为两个数据库事务是隔离的。请记住,对于护照和演示文稿任务,你是唯一的执行者

情况3:并行执行

现在,因为你是如此聪明的家伙,显然你已经是高层了,你有一个助手。所以,在你开始护照任务之前,你打电话告诉他准备好演示文稿的初稿。你整天都在完成护照任务,回来看你的邮件时,你发现了演示文稿的草稿。他已经做得很不错了,再编辑2个小时,你就最终确定了它。

现在,由于你的助手和你一样聪明,他能够独立地工作,而不需要经常向你询问澄清问题。因此,由于任务的独立性,两个执行者同时执行了这些任务。

还跟上吗?好的...

案例 4:并发但非并行

记得你的护照任务,需要排队等待吗? 既然这是你的护照,你的助手就不能代替你排队等待。因此,护照任务具有可中断性(你可以在排队等待时停止它,并在稍后当你的号码被叫到时恢复它),但没有独立性(你的助手不能代替你的位置排队等待)。

案例 5:并行但非并发

假设政府机构进行安全检查才能进入场所。在这里,你必须拿出所有电子设备并提交给警察,而他们只有在你完成任务后才会归还你的设备。

在这种情况下,护照任务既不具备独立性也不具备可中断性。即使你在排队等待时,也不能做其他事情,因为你没有必要的设备。

同样,假设演示文稿的性质非常数学化,你需要至少集中100%的注意力5小时。即使你带着笔记本电脑在等待护照任务的队列中,你也无法做到。

在这种情况下,演示文稿任务是独立的(你或你的助手都可以投入5小时的专注工作),但不具有可中断性

案例 6:并发和并行执行

现在,除了将你的助手分配给演示文稿外,你还携带一台笔记本电脑去完成护照任务。在等待排队时,你看到你的助手已经创建了一份共享的幻灯片前10页。你对他的工作进行评论并作出一些更正意见。后来,当你回到家时,你只需要15分钟就能完成最终的草稿,而不是原本需要2个小时。

这是可能的,因为演示文稿任务具有独立性(你们两个中的任何一个都可以完成它)和可中断性(你可以停止它并稍后恢复它)。因此,你可以同时执行两个任务,并在演示文稿任务中执行并行操作。

假设政府机构除了过于官僚外,还存在腐败。因此,你可以出示身份证明,进入场所并开始排队等待,贿赂一个警卫和另一个人来保持你在队列中的位置,溜走,在你的号码被叫到之前回来并继续等待。

在这种情况下,你可以同时且并行地执行护照和演示文稿任务。你可以离开,你的助手接替你的位置。你们两个都可以继续工作,等等。


回归计算机科学

在计算机领域中,以下是每种情况的典型示例:

  • 情况1:中断处理。
  • 情况2:当只有一个处理器,但所有执行任务由于I/O而有等待时间时。
  • 情况3:通常在讨论map-reduce或hadoop集群时看到。
  • 情况4:我认为情况4是罕见的。任务并发但不并行很不常见。但是它可能会发生。例如,假设您的任务需要访问仅可通过处理器1访问的特殊计算芯片。因此,即使处理器2空闲且处理器1正在执行其他任务,特殊计算任务也无法在处理器2上进行。
  • 情况5:也很少见,但不如情况4那么罕见。非并发代码可以是由互斥锁保护的关键区域。一旦启动,它必须执行完成。然而,两个不同的关键区域可以同时在两个不同的处理器上进行。
  • 情况6:在我看来,关于并行或并发编程的大多数讨论基本上都是在谈论情况6。这是并行和并发执行的混合。

并发和Go

如果你理解Rob Pike为什么说并发更好,你必须了解原因。你有一个非常长的任务,其中有多个等待时间,在这些等待期间您需要等待一些外部操作,如文件读取、网络下载。在他的讲座中,他只是在说:“只需将此长时间的顺序任务拆分,以便在等待时可以做一些有用的事情。”这就是为什么他谈论具有各种gopher的不同组织。

现在,Go语言的强大之处在于使用go关键字和通道使此打破变得非常容易。此外,运行时对调度这些goroutine提供了出色的底层支持。

但本质上,并发比并行更好吗?

苹果比橙子更好吗?


9
Node.js事件循环是案例4的一个很好的例子。即使处理器B有空闲资源,请求X也应该由正在处理Y的处理器A处理。如果为Y调用setTimeout,则可以处理X,然后在超时之后也将继续处理Y。 - Lucas Janon
5
值得注意的是,接受回答和此回答中“并发”一词的两个定义是相当不同的。第一个指的是在重叠时间段内运行多个任务的概念(即并行意味着并发),第二个指的是打断一项任务去运行其他任务的概念。 - Ilya Loskutov
1
这太棒了!! - Nikhil_10
2
换句话说:并发是指系统(线程、程序、语言)暂停执行一个任务,开始执行第二个任务,完成或暂停执行第二个任务,然后继续执行第一个任务等等。并行是指同时执行这两个任务(在并行中)。这种理解是否接近正确? - Sergio
1
这是一个非常好的解释。谢谢你,佩服! - Guillaume
显示剩余7条评论

278

我喜欢Rob Pike的演讲:并发不等于并行(它更好!)(幻灯片, 演讲录像)。

Rob通常谈论Go语言并回答并发与并行的问题,用直观的方式进行解释。以下是简短的总结:

任务:让我们一次烧掉一堆过时的语言手册!

Task

并发:有很多个并发分解这个任务!以下是一个例子:

Gophers

并行:如果至少有两只地鼠同时工作或者没有,则上述配置并行进行。


10
有关视频,请参见 https://blog.heroku.com/archives/2013/2/24/concurrency_is_not_parallelism - Pramod
30
抱歉,我不得不对“更好”的部分进行投票否决。正确的答案是它们是不同的。并发是问题的一部分,而并行是解决方案的一部分。 - isekaijin
@EduardoLeón,你显然没有检查演讲的名称。并发不是问题,它只是思考问题/任务的一种方式。 - asfer
6
并发是问题结构的一部分。顺便说一句,不要混淆“并发”(问题本身)和“并发控制”(一个解决方案,通常与并行一起使用)。 - isekaijin
2
我看了它,老实说我不喜欢。它给本应该用更简单的方式解释的东西增加了不必要的复杂性和书呆子气息(在这里查看Juggler的答案)。 - Redoman

191

假设你有一个包含两个线程的程序。该程序可以以两种方式运行:

Concurrency                 Concurrency + parallelism
(Single-Core CPU)           (Multi-Core CPU)
 ___                         ___ ___
|th1|                       |th1|th2|
|   |                       |   |___|
|___|___                    |   |___
    |th2|                   |___|th2|
 ___|___|                    ___|___|
|th1|                       |th1|
|___|___                    |   |___
    |th2|                   |   |th2|
在这两种情况下,我们都有并发性,因为我们有多个线程在运行。
如果我们在单核心的计算机上运行此程序,操作系统将在两个线程之间切换,并允许一个线程一次运行。
如果我们在多核的计算机上运行此程序,那么我们可以并行运行这两个线程-同时并排地运行。

12
我喜欢这些线块。简单而完美!感谢你提供如此精彩的答案。 - bozzmob
不错的例子。我推断当有单核 CPU 时,你只能拥有并发而不是并行。并发 = 进程轮流执行(不像顺序执行)。 - Abdel Aleem
可能添加一个纯并行性的示例会很有帮助。 - Ibraheem Ahmed
@IbraheemAhmed 什么是“纯并行性”?没有并发就没有并行。 - Pithikos
@IbraheemAhmed 我认为你在谈论接近硬件的较低级别。在我们的情况下,并发和并行是从程序员的角度来看时间切片的问题。归根结底,程序员只能使用操作系统提供的API。 - Pithikos
显示剩余3条评论

183

补充其他人所说的内容:

并发就像一个杂技演员同时抛接很多球一样。不管看起来怎么样,杂技演员每次只能用一只手接/抛一个球。并行是指同时有多个杂技演员同时抛接球。


3
如果你手里握着偶数个球,那么你在抛接球时是可以同时拿起两个球的(具体取决于你的抛接方式)。 - thebugfinder
84
为了确保Thomas的例子没有更多错误,需要说明一下并发和并行的区别。并发就像一个人只用一只手来玩接球游戏,尽管看起来他好像同时抓住了许多球,但实际上他每次最多只能抓住一个球。而并行则是当接球者使用两只手时的情况。 - bigtunacan
我实际上想表达的是“偶数个球”,而不是“成对数目的球”。 - thebugfinder
1
非常聪明的回答。我肯定能理解thebugfinder的观点,但如果考虑并达成一次只执行一个操作,我非常喜欢这个答案。 - B.K.
3
我认为“并行性是每个球都有一个人来控制”更好。如果球的数量增加(比如想象一下网络请求),这些人可以开始杂耍,使执行变得并发和并行。此外,如果有人能够用杂技演员的例子来解释反应器模式,那就太好了。 - Redoman
显示剩余2条评论

65

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

alt text

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

alt text


61
我不同意这个说法 - 一个旨在并发运行的程序可能会或可能不会同时运行; 并发更多是程序的属性,当它执行时可能会出现并行。 - Adrian Mouat

63

想象通过观看视频教程学习一门新的编程语言。您需要暂停视频,将所说的内容应用到代码中,然后继续观看。这就是并发。

现在您是一名专业程序员。您喜欢在编码时听轻松的音乐。这就是并行。

正如安德鲁·格兰德在GoLang博客中所说:

并发是关于同时处理许多事情。并行则是同时进行许多事情。

享受吧。


56

我将尝试用一个有趣且易于理解的例子来解释。

假设一个组织举办了一场国际象棋锦标赛,其中10名拥有相同棋艺水平的选手将挑战一名职业冠军选手。由于国际象棋是一种1:1的游戏,因此组织者必须以时间有效的方式进行10场比赛,以便尽快完成整个比赛。

以下情况将很容易描述如何进行这10场比赛:

1) 串行 - 职业选手依次与每个人对局,即与一名选手开始并结束游戏,然后再开始下一场比赛,并且他们决定按顺序进行比赛。因此,如果一场比赛需要10分钟才能完成,则10场比赛将需要100分钟,还要假设从一个比赛到另一个比赛的转换需要6秒钟,那么在10场比赛中需要54秒钟(约1分钟)。

因此,整个事件将在101分钟内完成(最糟糕的方法)。

2) 并行 - 职业选手轮流与每个选手一起玩,因此所有10名选手同时进行比赛,但职业选手不会与两个人玩在一起,他会完成自己的回合并进入下一个人的游戏。现假设职业选手需要6秒钟来完成自己的回合,并且两名选手之间的转换时间为6秒钟,因此总转换时间将为1分钟(10x6秒)。因此,在他回到第一个参赛者之前,已经过去了2分钟(10x职业选手每回合所需时间+ 10x转换时间= 2分钟)。

假设所有选手都需要45秒才能完成自己的回合,则根据串行事件中每场比赛需要10分钟的时间,每个游戏结束之前应进行11轮比赛(约)。

所以整个比赛将大约在11x每位玩家和冠军的每回合时间+ 11x跨越10个玩家的过渡时间完成= 11x51 + 11x60秒= 561 + 660 = 1221秒= 20.35分钟(大约)

从101分钟到20.35分钟,见证了明显的改善(更好的方法

3)并行 - 假设主办方得到了一些额外的资金,因此决定邀请两名职业选手(都同样有能力),并将相同的10名玩家(挑战者)分成两组,每组5人,并将他们分配给两个冠军,即每个组一个。现在,在这两组中至少有两名玩家(每组一个)正在与其各自组的两名职业选手比赛。

但是,在小组内,职业球员将逐个地接受一名球员(即按顺序),因此您可以轻松推断出整个事件将大约需要50.5分钟才能完成,无需任何计算。

从101分钟到50.5分钟,见证了明显的改善(良好的方法

4)并发+并行 - 在上述情况下,假设两个冠军选手将与其各自组的5名球员同时进行比赛(参见第2点),因此现在组间游戏并行运行,但是在小组内部游戏会同时进行。

因此,一个小组中的比赛将大约在11x每位玩家和冠军的每回合时间+ 11x跨越5个玩家的过渡时间完成= 11x51 + 11x30 = 600 + 330 = 930秒= 15.5分钟(大约)

因此,整个比赛(涉及两个这样并行运行的小组)将大约需要15.5分钟才能完成。

从101分钟到15.5分钟,见证了明显的改善(最佳方法

注意: 在上述场景中,如果您将10个球员替换为10个类似的工作,并将两名职业球员替换为两个CPU核心,则以下排序仍将保持不变:

串行 > 并行 > 并发 > 并发 + 并行

(注意:对于其他情况,此顺序可能会改变,因为这种排序高度取决于作业之间的相互依赖性,作业之间的通信需求和转换开销)


4
很好的解释。还有一点需要补充,当职业选手在两个玩家之间移动时,如果选手在45秒内完成自己的回合,同时使用并发模型才能得到提高。换句话说,在整个过程中我们应该有I/O等待。如果普通玩家的回合时间少于45秒(可能为5或10秒),改进将会较小。因此,如果我们的工作中没有I/O等待时间,那么并发将与串行执行大致相同。 - Psylone
1
我认为这是最好的解释,因为我一直在努力理解“并发+并行”场景。在阅读这个答案之前,我总是认为“并行性”比“并发性”更好,但显然,这取决于资源限制。你越像一个“职业国际象棋选手”,与并发性相比,你的表现会更好。 - Hmerac

48

并发编程执行有两种类型:非并行并发编程和并行并发编程(也称为并行性)。

关键的区别在于,对于人眼来说,在非并行并发中,线程似乎同时运行,但实际上并不是这样。在非并行并发中,线程通过时间片轮流快速切换使用处理器。而在并行性中,有多个处理器可用,因此多个线程可以同时在不同的处理器上运行。 输入图片说明

参考:编程语言中的并发介绍


17
一张图片胜过千言万语。 - senseiwu
很好地强调了并行性只是并发的一种类型,它是由硬件实现的。这就是许多人,包括我自己,感到困惑的地方。 - uzluisf

41

并行性是在具有多核 CPU单个主板上的多个 CPU的计算机上同时运行进程。

并发性是指在单个核心/CPU上通过使用调度算法(时间片)实现并行性。进程会被交错执行

单位:

  • 一个 CPU 中有一个或多个核心(几乎所有现代处理器都有)
  • 一个主板上有一个或多个 CPU(类似老式服务器)
  • 一个应用程序就是一个程序(如 Chrome 浏览器)
  • 一个程序可以有一个或多个进程(如每个 Chrome 浏览器选项卡)
  • 一个进程可以有来自同一程序的一个或多个线程(Chrome 选项卡中播放 YouTube 视频的一个线程,评论部分产生的另一个线程,用户登录信息的另一个线程)
  • 因此,一个程序可以有一个或多个执行线程
  • 一个进程是线程(s)+操作系统分配的内存资源(堆、寄存器、栈、类内存)

5
我认为这是计算机科学领域的完美答案。 - sofs1
3
这个答案应该被采纳,而不是上面和下面的哲学思考。 - EugenSunic
1
这个答案部分是错误的,虽然并行是实现并发的一种方式,但异步运行时是另一种方式。甚至有多线程异步运行时。 "并发" 这个词并不意味着单个核心/ CPU。 - Finomnis
1
并行性不能在单个核心/CPU上“实现”。 答案中提供的第一种并行定义是正确的。 给出的第二种并发定义是错误的,并与第一种定义相矛盾。 如果并行性需要多核或多个处理器,那么如何在单个核心上实现并行性? - Abul Fayes
并发是在单个核心/ CPU 上实现并行性时发生的。这是错误的,因为在单个CPU上无法实现并行性,因为并行性的定义就是“同时/在一个时间点/瞬间”执行多个事情,而在单个CPU上无法做到这一点。在单个CPU上,CPU在不同任务之间切换上下文,导致它们的执行交错进行,但一次只有一个任务正在执行。并发任务可以在适当的硬件支持下可能并行运行,例如多核CPU。 - uzluisf
Chrome每个标签页播放YouTube视频时会生成一个线程,另外一个线程用于评论区,还有一个线程用于用户登录信息。Chrome为每个标签页生成一个进程,这样可以确保一个标签页崩溃不会影响其他标签页,因为进程之间不共享地址空间。每个进程都有独立的地址空间,与线程不同。 - uzluisf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接