ChatGPT解决这个技术问题 Extra ChatGPT

并发和并行有什么区别?

并发和并行有什么区别?

简短的回答:并发是两行客户从一个收银员那里订购(线路轮流订购);并行性是两行客户从两个收银员处订购(每行都有自己的收银员)。
@chharvey:我真的认为这应该是答案。简短(两行文字,如果您不使用“简短答案”),中肯,立即可以理解。做得很好!
记住这个比喻的助记符:并发==同时客户;并行 == 同时支付
IMO,这个问题几乎是每个程序员都觉得有必要问的一个问题。就我自己而言,我已经问过这个问题,并多次问过其他人。因此,我认为在这里提出这个问题的第一个用户应该是唯一能够选择正确答案的用户是不正确的。我投票正确的答案是:stackoverflow.com/a/53992216/1365918
@chharvey 的简短回答很棒。我想再补充一句来真正拼写出来:“这里,每个收银员代表你机器的一个处理核心,客户是程序指令。”

R
Rick

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

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

引用Sun's Multithreaded Programming Guide

并发:当至少有两个线程在进行时存在的条件。一种更通用的并行形式,可以将时间分片作为一种虚拟并行形式。

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


我喜欢这个答案,但我可能会更进一步,将并发性描述为程序或系统的属性(并行性是同时执行多个任务的运行时行为)。
我非常喜欢 Adrian Mouat 的评论。另请参阅这个出色的解释:haskell.org/haskellwiki/Parallelism_vs._Concurrency
@Raj:正确,单核处理器不可能实现并行性(在多线程的意义上)。
如果 Sequential 和 Parallel 都是枚举中的值,那么该枚举的名称是什么?
为此,Sun 的引言可以改写为: - 并发:在给定的时间段内,两个线程正在取得进展时存在的条件 - 并行:在给定特定时间点,两个线程时出现的条件正在同时执行
P
Pankaj

为什么存在混乱

存在混淆是因为这两个词的字典含义几乎相同:

并发:同时存在、发生或完成(dictionary.com)

并行:非常相似并且经常同时发生(韦伯斯特)。

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

并发性:可中断性

并行性:独立性

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

我将用一个现实世界的类比来澄清。假设您必须在一天内完成两项非常重要的任务:

获得护照 完成演示

现在,问题是任务 1 要求你去一个极其官僚的政府办公室,让你排队等待 4 个小时才能拿到护照。同时,您的办公室需要task-2,这是一项关键任务。两者都必须在特定日期完成。

案例一:顺序执行

通常情况下,你会开车去护照办公室 2 小时,排队 4 小时,完成任务,开车回去 2 小时,回家,再睡 5 小时,然后完成演示。

案例 2:并发执行

但是你很聪明。你提前计划。您随身携带一台笔记本电脑,在排队等候时,您开始处理您的演示文稿。这样,一旦你回到家,你只需要多工作 1 小时而不是 5 小时。

在这种情况下,这两项任务都由您完成,只是部分完成。您在排队等候时打断了护照任务并进行演示。当您的号码被呼叫时,您中断了演示任务并切换到护照任务。由于这两个任务的可中断性,基本上可以节省时间。

并发,IMO,可以理解为ACID中的“隔离”属性。如果子事务可以以每种和任何交错方式执行并且最终结果与两个任务按顺序完成一样,则认为两个数据库事务是隔离的。请记住,对于护照和演示任务,您是唯一的刽子手

案例 3:并行执行

现在,你这么聪明的家伙,明明是高人一等,还有助手。所以,在你离开开始护照任务之前,你打电话给他并告诉他准备演示文稿的初稿。你花了一整天的时间完成护照任务,回来查看邮件,然后找到演示文稿草稿。他做得很扎实,在两个多小时内进行了一些编辑,你完成了它。

现在,由于您的助手和您一样聪明,他能够独立工作,而无需不断要求您澄清。因此,由于任务的独立性,它们由两个不同的刽子手同时执行。

还在我这儿?好吧...

案例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:IMO,大多数关于并行或并发编程的讨论基本上都是在谈论案例6。这是并行和并发执行的混合和匹配。

并发和 Go

如果你明白为什么 Rob Pike 说并发更好,你就必须明白原因是什么。您有一个非常长的任务,其中有多个等待期,您需要等待一些外部操作,如文件读取、网络下载。在他的演讲中,他所说的只是,“把这个冗长的连续任务分解,这样你就可以在等待的时候做一些有用的事情。”这就是为什么他用各种地鼠谈论不同的组织。

现在,Go 的强大之处在于使用 go 关键字和频道使这种突破变得非常容易。此外,运行时中有出色的底层支持来调度这些 goroutine。

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

苹果比橙子好吗?


感谢案例 5。我经常认为并行隐式意味着并发。
Node.js 事件循环是案例 4 的一个很好的例子。即使处理器 B 有空闲资源,请求 X 也应该由忙于处理 Y 的处理器 A 处理。如果为 Y 调用 setTimeout,则可以处理 X,那么,超时后 Y 也将结束处理。
值得注意的是,“并发”一词的两个定义已被放入已接受的答案中,而这个定义是截然不同的。第一个是指在重叠的时间段内运行多个任务的概念(即并行性意味着def并发),第二个是指中断一个任务以运行另一个任务的概念。
与上面的评论类似 - 多线程 python 是案例 4 的一个示例。我认为这种情况并不罕见。任何全局解释器锁都将导致情况 4(如果它完全允许并发)。
我认为案例 5(并行但非并发)是一种误导性事实,因为所有并行程序都是并发程序的子集
K
Kyle G

我喜欢 Rob Pike 的演讲:并发不是并行(它更好!)(slides) (talk)

Rob 通常会谈论 Go,并且通常会以视觉和直观的解释来解决并发与并行的问题!这是一个简短的摘要:

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

https://i.stack.imgur.com/C37MJ.jpg

并发:任务有很多并发分解!一个例子:

https://i.stack.imgur.com/w4HUK.jpg

并行性:如果至少有 2 个地鼠同时工作,则前面的配置并行发生。


有关视频,请参阅 blog.heroku.com/archives/2013/2/24/…
抱歉,不得不为“它更好”位投反对票。正确答案是不同。并发是问题的一部分。并行性是解决方案的一部分。
@EduardoLeón 你显然没有检查谈话的名称。并发不是问题,它只是思考问题/任务的一种方式。
@asfer 并发是问题结构的一部分。顺便说一句,不要将“并发”(问题)与“并发控制”(一种解决方案,通常与并行性一起使用)混为一谈。
我看了它,老实说我不喜欢它。它为应该以更简单的方式解释的事情增加了不必要的复杂性和书呆子(查看杂耍者的答案)。
A
Asclepius

补充其他人所说的话:

并发就像让一个杂耍者玩很多球。不管看起来如何,杂耍者一次只能接/扔一个球。并行性是让多个杂耍者同时玩球。


我会很挑剔,但如果你用一对球玩杂耍,你可以同时拥有两个球(取决于你如何玩杂耍)。
@thebugfinder,为了确保在 Thomas 的示例中不再有错误的余地。并发就像一个人只用一只手玩杂耍。不管看起来如何,这个人一次最多只能拿着一个球。平行是指杂耍者使用双手。
我实际上想说的是“球对数”是“偶数球”
很聪明的回答。我绝对可以看到错误发现者的观点,但是如果一次考虑并同意一项操作,我会非常喜欢这个答案。
我认为“并行性是每个球都有一个人”更好。如果球的数量增加(想象一下网络请求),这些人可以开始玩杂耍,使执行并发和并行。我也很想有人可以用杂耍者的例子来解释反应堆模式..
l
lucid_dreamer

假设您有一个有两个线程的程序。该程序可以通过两种方式运行:

Concurrency                 Concurrency + parallelism
(Single-Core CPU)           (Multi-Core CPU)
 ___                         ___ ___
|th1|                       |th1|th2|
|   |                       |   |___|
|___|___                    |   |___
    |th2|                   |___|th2|
 ___|___|                    ___|___|
|th1|                       |th1|
|___|___                    |   |___
    |th2|                   |   |th2|

在这两种情况下,我们都具有并发性,因为我们有多个线程在运行。

如果我们在具有单个 CPU 内核的计算机上运行此程序,操作系统将在两个线程之间切换,允许一次运行一个线程。

如果我们在具有多核 CPU 的计算机上运行此程序,那么我们将能够并行运行两个线程——同时并排运行。


我喜欢线程块。简单却完美!谢谢你这么棒的回答。
很好的例子。我推断,当有单核 CPU 时,你只能有并发,而不能有并行。并发=进程轮流(与顺序不同)
也可能有助于添加纯并行的示例。
@IbraheemAhmed 什么是“纯并行”?没有并发就没有并行。
没有并发的 SIMD 操作不是并行性吗?
R
Rajendra Uppal

https://i.stack.imgur.com/OdYWr.gif

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

https://i.stack.imgur.com/RRF1J.gif


我不同意这一点——设计为并发的程序可能会或可能不会并行运行;并发更多是程序的属性,执行时可能会出现并行。
R
Ramy M. Mousa

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

现在你是一个专业的程序员。而且你喜欢在编码时听平静的音乐。这就是并行。

正如 Andrew Gerrand 在 GoLang Blog 中所说

并发是一次处理很多事情。并行性是关于一次做很多事情。

享受。


P
Pankaj

我将尝试用一个有趣且易于理解的示例进行解释。 :)

假设一个组织组织了一场国际象棋锦标赛,其中 10 名棋手(棋手水平相同)将挑战一名职业棋手。由于国际象棋是1:1的比赛,因此组织者必须以高效的方式进行10场比赛,以便他们尽快完成整个赛事。

希望以下场景能够轻松描述进行这 10 场比赛的多种方式:

1) SERIAL - 假设专业人士与每个人一个接一个地比赛,即与一个人开始和结束比赛,然后与下一个人开始下一场比赛,依此类推。换句话说,他们决定按顺序进行游戏。因此,如果一场比赛需要 10 分钟才能完成,那么 10 场比赛将需要 100 分钟,还假设从一场比赛过渡到另一场比赛需要 6 秒,那么 10 场比赛将需要 54 秒(大约 1 分钟)。

所以整个活动将在 101 分钟内完成(最差方法)

2) 并发 - 假设职业选手轮到下一位选手,所以所有 10 位选手同时比赛,但职业选手一次不是两个人,他轮到他轮到下一位选手.现在假设一个职业玩家需要 6 秒来玩他的回合,并且一个职业玩家黑白两个玩家的转换时间是 6 秒,所以回到第一个玩家的总转换时间将是 1 分钟(10x6 秒)。因此,当他回到比赛开始的第一个人时,已经过去了 2 分钟(10xtime_per_turn_by_champion + 10xtransition_time=2mins)

假设所有玩家需要 45 秒来完成他们的回合,因此基于从 SERIAL 事件开始的每场比赛 10 分钟,没有。比赛结束前的回合数应为 600/(45+6) = 11 回合(大约)

所以整个赛事大约会在 11xtime_per_turn_by_player_&_champion + 11xtransition_time_across_10_players = 11x51 + 11x60sec= 561 + 660 = 1221sec = 20.35 分钟内完成(大约)

查看从 101 分钟到 20.35 分钟的改进(更好的方法)

3) 平行 - 假设组织者获得了一些额外的资金,因此决定邀请两名职业冠军选手(两人能力相同)并将相同的 10 名选手(挑战者)分成两组,每组 5 人,并将他们分配给两个冠军,即一个每个分组。现在该赛事在这两组中并行进行,即至少有两名球员(每组一名)正在与各自组中的两名职业球员比赛。

然而,在组内,职业选手一次带一名选手(即顺序),因此无需任何计算,您可以轻松推断出整个赛事将在 101/2=50.5 分钟内完成

看到从 101 分钟到 50.5 分钟的改进(好的方法)

4) CONCURRENT + PARALLEL - 在上述场景中,假设两名冠军玩家将与各自组中的 5 名玩家同时玩(读取第 2 点),所以现在跨组的游戏并行运行,但在组内,他们正在运行同时。

因此,一组中的游戏将大约在 11xtime_per_turn_by_player_&_champion + 11xtransition_time_across_5_players = 11x51 + 11x30 = 600 + 330 = 930sec = 15.5 分钟内完成(大约)

所以整个活动(涉及两个这样的平行跑组)大约在15.5分钟内完成

查看从 101 分钟到 15.5 分钟的改进(最佳方法)

注意:在上面的场景中,如果你用 10 个类似的工作替换 10 个玩家,用两个 CPU 核心替换两个职业玩家,那么下面的顺序仍然是正确的:

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

(注意:此顺序可能会因其他情况而改变,因为此顺序高度依赖于作业的相互依赖性、作业之间的通信需求以及作业之间的转换开销)


很好的解释。有一个补充。第二种情况的并发模型(当职业玩家移动黑白玩家时)只有当玩家在 45 秒内轮到自己时才会得到改进。换句话说,我们应该在整个过程中等待 I/O。如果普通玩家可以在不到 45 秒(5 秒或可能是 10 秒)内上交,则改进会更少。因此,如果我们的工作中没有 I/O 等待时间,并发性将与串行执行大致相同。
我认为这是最好的解释,因为我一直在努力解决“并发+并行”场景。同样在阅读此答案之前,我一直认为“并行”比“并发”更好,但显然,这取决于资源限制。您获得的“职业棋手”越多,与并发相比,您的表现就越好。
S
Saurabh Pakhare

简单的例子:

并发是:“两个队列访问一台 ATM 机”

并行是:“两个队列和两个 ATM 机”


还有多线程?只是想一想多线程一词如何适合上述情况。在这种情况下,并发 == 多线程,就像每个队列中的一个每个时刻都去 ATM 一样?
@KhoPhi 多线程意味着并发,但并不意味着并行。如果我错了,有人纠正我。
n
nabster

并行性 是在 multiple cores per CPUmultiple CPUs (on a single motherboard) 上同时执行进程。

并发是指通过使用划分 CPU 时间(时间片)的调度算法single core/CPU 上实现并行。进程是交错的

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


我认为这是计算机科学界的完美答案。
这个答案应该是公认的答案,而不是上面和下面的哲学
A
Apurva Thorat

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

https://i.stack.imgur.com/mUlNV.jpg

参考:Introduction to Concurrency in Programming Languages


一张千言万语的图
J
JP Alioto

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

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


M
Mihai Toader

并发性:具有共享资源潜力的多个执行流程

例如:两个线程竞争一个 I/O 端口。

并行性:将问题分成多个相似的块。

例如:通过在文件的每一半上运行两个进程来解析一个大文件。


W
Will Ness

并发 => 当多个任务在重叠的时间段内使用共享资源执行时(可能最大化资源利用率)。

Parallel => 当单个任务被分成多个可以同时执行的简单独立子任务时。


您如何描述多任务(时间片)以呈现重叠处理的单核处理器系统?当并发定义为在重叠时间段内执行时,它包括此处理。您已经描述了根据您的并发定义将其排除在外的同时执行。
最好的定义恕我直言,但您应该将“共享资源”更改为“共享可变资源”。
y
yoAlex5

并发与并行

'Concurrency Is Not Parallelism' 中的罗布·派克

并发是一次处理很多事情。

并行性是关于一次做很多事情。

[Concurrency theory]

并发性——一次处理多个任务并行性——一次处理多个线程

我对并发和并行的看法

[Sync vs Async]


R
Rahul

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

1 个服务器,1 个作业队列(有 5 个作业)-> 没有并发,没有并行性(只有一个作业正在完成,队列中的下一个作业必须等到服务的作业完成并且没有其他服务器可以服务它)

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

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

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

换句话说,并发是共享时间来完成一项工作,它可能会占用相同的时间来完成它的工作,但至少它开始得早。重要的是,工作可以被分割成更小的工作,这允许交错。

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

请记住,如果资源是共享的,则无法实现纯粹的并行性,但这是并发具有最佳实际用途的地方,它占用了另一个不需要该资源的工作。


d
dangom

我真的很喜欢 Paul Butcher 对这个问题的answer(他是七周内的七个并发模型的作者):

尽管它们经常被混淆,但并行性和并发性是不同的东西。并发是问题域的一个方面——您的代码需要处理多个同时(或接近同时)的事件。相比之下,并行性是解决方案域的一个方面——您希望通过并行处理问题的不同部分来使程序运行得更快。有些方法适用于并发,有些适用于并行,有些适用于两者。了解您面临的问题并为工作选择合适的工具。


A
Amit Meena

如果你想向一个 9 岁的孩子解释这一点。

https://i.stack.imgur.com/ZqHC3.gif


s
s1l3n0

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

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

串行/并行和顺序/并发特性是正交的。这方面的一个例子是数字通信。在串行适配器中,数字消息在时间上(即顺序地)沿着相同的通信线路(例如,一根线)分布。在并行适配器中,这也在并行通信线路(例如多条线路)上进行划分,然后在接收端进行重构。

让我们想象一个有 9 个孩子的游戏。如果我们将它们作为一个链来处理,首先发出一条消息,最后接收它,我们将进行串行通信。更多的词组成了信息,由一系列通信单元组成。

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

这是在串行基础设施上重现的顺序过程。

现在,让我们想象将孩子分成 3 个一组。我们将短语分成三部分,第一个给我们左边那一行的孩子,第二个给中间线的孩子,依此类推。

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

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

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

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


+1 有趣。在计算一个定义时,根据当前接受的答案,并发意味着在重叠的时间段内执行,不一定同时执行(这将是并行的)。在电子学中,您如何描述旨在呈现同时发生的事物的外观但只是快速切换的电路。继续你的冰淇淋类比:我非常喜欢冰淇淋>孩子A1我喜欢>孩子B1冰淇淋>孩子C1非常>孩子A2我喜欢>孩子B2冰淇淋<孩子C2这么多......
我在这里第一次看到这个:s1l3n0.blogspot.com/2013/04/…
是的,我在我的一篇个人博客笔记中改进/扩展了我的答案。 ;)
B
Ben Ylvisaker

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

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

关于并行性的更多细节:

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

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

关于交互性的更多细节:

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

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

脾气暴躁

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


C
Community

来自 Robert Love 的 Linux System Programming 一书:

并发、并行和竞态线程创建了两种相关但截然不同的现象:并发和并行。两者都是苦乐参半,触及线程的成本以及它的好处。并发性是两个或多个线程在重叠时间段内执行的能力。并行性是同时执行两个或多个线程的能力。并发可以在没有并行性的情况下发生:例如,单处理器系统上的多任务处理。并行性(有时强调为真正的并行性)是一种特定形式的并发,需要多个处理器(或能够执行多个引擎的单个处理器,例如 GPU)。通过并发,多个线程向前推进,但不一定同时进行。使用并行性,线程实际上是并行执行的,允许多线程程序利用多个处理器。并发是一种编程模式,一种解决问题的方法。并行性是一种硬件功能,可以通过并发来实现。两者都很有用。

这个解释与公认的答案是一致的。实际上,这些概念远比我们想象的要简单。不要认为它们是魔法。并发性大约是一段时间,而并行性大约是同时,同时。


佚名

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

在单个处理器上可以并发执行(多个线程,由调度程序或线程池管理) 在单个处理器上不能在多个处理器上并行执行。 (每个处理器一个进程)分布式计算也是一个相关主题,它也可以称为并发计算,但反向不是真的,如并行。

有关详细信息,请阅读此研究论文 Concepts of Concurrent Programming


C
Community

我真的很喜欢另一个答案的这个图形表示 - 我认为它比上述许多答案更好地回答了这个问题

Parallelism vs Concurrency 当两个线程并行运行时,它们都同时运行。例如,如果我们有两个线程,A 和 B,那么它们的并行执行将如下所示:

CPU 1:A ------------->

CPU 2:B ------------->

当两个线程同时运行时,它们的执行重叠。重叠可以通过以下两种方式之一发生:线程同时执行(即并行,如上所述),或者它们的执行在处理器上交错,如下所示:

CPU 1:A ------------> B ----------> A -----------> B -------- -->

所以,为了我们的目的,并行可以被认为是并发的一个特例

来源:Another answer here

希望有帮助。


B
Branko Dimitrijevic

“并发”是指有多个正在进行的事情。

“并行”是指同时进行的事情。

没有并行性的并发示例:

单个内核上的多个线程。

Win32 消息队列中的多条消息。

MARS 连接上的多个 SqlDataReader。

浏览器选项卡中的多个 JavaScript 承诺。

但是请注意,并发性和并行性之间的区别通常是一个角度问题。从执行代码(可观察到的效果)的角度来看,上述示例是不平行的。但即使在单个内核中也存在指令级并行性。有一些硬件与 CPU 并行执行操作,然后在完成时中断 CPU。当您 window procedure 或事件处理程序正在执行时,GPU 可能正在绘制到屏幕上。 DBMS 可能正在为下一个查询遍历 B 树,而您仍在获取前一个查询的结果。执行 Promise.resolve() 时,浏览器可能正在布局或联网。等等等等……

所以你去。世界一如既往的混乱;)


并发性和并行性之间的区别通常是一个角度问题。我喜欢这句话和它的例子。并行性的存在取决于观察者所在的位置以及正在观察的内容。
D
Daniel Soutar

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

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

那么为什么不让一切都平行呢?一个原因是因为并发是一种结构化程序的方式,并且是一种促进关注点分离的设计决策,而并行性通常以性能的名义使用。另一个是有些事情根本上不能完全并行完成。这方面的一个例子是将两个东西添加到队列的后面 - 你不能同时插入两个东西。有些东西必须先走,然后再走,否则你会弄乱队列。虽然我们可以交错这样的执行(因此我们得到一个并发队列),但你不能让它并行。

希望这可以帮助!


G
Geoffrey Anderson

“并发”是同时做事情——任何事情。它们可能是不同的东西,也可能是相同的东西。尽管缺乏公认的答案,但这并不是“看起来同时”。真的是同时。您需要多个 CPU 内核,或者在一台主机中使用共享内存,或者在不同主机上使用分布式内存,以运行并发代码。同时运行的 3 个不同任务的管道就是一个示例:任务级别 2 必须等待任务级别 1 完成的单元,任务级别 3 必须等待任务级别完成的工作单元任务级别 2。另一个例子是 1-producer 与 1-consumer 的并发;或多生产者和 1 消费者;读者和作家;等。

“并行”是在同一时间做同样的事情。它是并发的,但此外,它是同时发生的相同行为,最常见的是在不同的数据上。矩阵代数通常可以并行化,因为您重复运行相同的操作:例如,可以使用相同的行为(和)但在不同的列上同时计算矩阵的列和。在可用处理器内核之间划分(拆分)列是一种常见的策略,以便每个处理器内核处理的工作量(列数)接近相同。拆分工作的另一种方法是任务袋,完成工作的工人回到经理处,经理分配工作并动态地获得更多工作,直到一切都完成。票务算法是另一个。

不仅仅是数字代码可以并行化。文件经常可以并行处理。在自然语言处理应用程序中,对于数百万个文档文件中的每一个,您可能需要计算文档中的标记数。这是并行的,因为您正在为每个文件计算令牌,这是相同的行为。

换句话说,并行性是同时执行相同的行为。 Concurrently 意味着同时,但不一定是相同的行为。并行是一种特殊的并发,其中同一件事同时发生。

例如,术语将包括原子指令、关键部分、互斥、自旋等待、信号量、监视器、屏障、消息传递、map-reduce、心跳、环、票务算法、线程、MPI、OpenMP。

Gregory Andrews 的著作是这方面的顶级教科书:多线程、并行和分布式编程。


与上述任何其他答案相比,我更喜欢这个答案。我认为对所提问题的回答不需要深入研究与内核数量、调度、线程等相关的任何内容。并发和并行性也是计算之外存在的概念,这是唯一的答案无论我是否在讨论计算,都以一种有意义的方式解释了这些概念。
k
kboom

并发性可以涉及同时运行或不同时运行的任务(它们确实可以在单独的处理器/内核中运行,但它们也可以在“滴答”中运行)。重要的是并发总是指完成一项更大的任务。所以基本上它是一些计算的一部分。你必须聪明地知道你可以同时做什么,不做什么以及如何同步。

并行性意味着你只是同时做一些事情。他们不需要成为解决一个问题的一部分。例如,您的线程可以分别解决一个问题。当然同步的东西也适用,但从不同的角度来看。


S
Sudip Bhandari

并行性:让多个线程执行类似的任务,这些任务在它们所需的数据和资源方面彼此独立。例如:谷歌爬虫可以产生数千个线程,每个线程可以独立完成它的任务。

并发性:当您在线程之间共享数据和共享资源时,就会出现并发性。在事务系统中,这意味着您必须使用锁、信号量等技术来同步代码的关键部分。


这应该是 IMO 公认的答案,因为它抓住了这两个术语的本质。
B
Boolean_Type

this source 的解释对我有帮助:

并发与应用程序如何处理它所处理的多个任务有关。应用程序可以一次处理一个任务(顺序)或同时处理多个任务(并发)。另一方面,并行性与应用程序如何处理每个单独的任务有关。应用程序可以从头到尾顺序处理任务,或者将任务拆分为可以并行完成的子任务。如您所见,应用程序可以是并发的,但不是并行的。这意味着它同时处理多个任务,但这些任务不会分解为子任务。应用程序也可以是并行的,但不是并发的。这意味着应用程序一次只能处理一个任务,并且该任务被分解为可以并行处理的子任务。此外,应用程序既不能是并发的,也不能是并行的。这意味着它一次只能处理一个任务,并且该任务永远不会分解为并行执行的子任务。最后,应用程序也可以是并发和并行的,因为它既可以同时处理多个任务,也可以将每个任务分解为子任务以并行执行。但是,在这种情况下,并发性和并行性的一些好处可能会丢失,因为计算机中的 CPU 已经相当忙于并发性或并行性。结合它可能只会导致很小的性能提升甚至性能损失。


这已在 this existing answer 中发布。
P
Pang

并发编程关注看似重叠的操作,主要关注由非确定性控制流引起的复杂性。与并发程序相关的定量成本通常是吞吐量和延迟。并发程序通常受 IO 限制,但并非总是如此,例如并发垃圾收集器完全在 CPU 上。并发程序的教学示例是网络爬虫。该程序启动对网页的请求,并在下载结果可用时同时接受响应,累积一组已访问过的页面。控制流是不确定的,因为每次运行程序时不一定以相同的顺序接收响应。这个特性会使调试并发程序变得非常困难。一些应用程序基本上是并发的,例如 Web 服务器必须同时处理客户端连接。 Erlang 可能是最有前途的高并发编程语言。并行编程涉及为提高吞吐量的特定目标而重叠的操作。通过使控制流具有确定性,可以避免并发编程的困难。通常,程序会生成并行运行的子任务集,并且父任务仅在每个子任务完成后才继续。这使得并行程序更容易调试。并行编程的难点在于针对粒度和通信等问题的性能优化。后者在多核环境中仍然是一个问题,因为将数据从一个缓存传输到另一个缓存会产生相当大的成本。密集矩阵-矩阵乘法是并行编程的一个教学示例,它可以通过使用 Straasen 的分治算法和并行攻击子问题来有效地解决。 Cilk 可能是在共享内存计算机(包括多核)上进行高性能并行编程的最有前途的语言。

复制自我的回答:https://stackoverflow.com/a/3982782