提问人:StackUnderflow 提问时间:6/27/2009 最后编辑:Stephen OstermillerStackUnderflow 更新时间:9/13/2023 访问量:361012
并发性和并行性有什么区别?
What is the difference between concurrency and parallelism?
答:
并发: 具有共享资源潜力的多个执行流
前任: 两个线程争用一个 I/O 端口。
Paralelism(平行) 将问题拆分为多个相似的块。
前任: 通过对文件的每一半运行两个进程来解析大文件。
并发是指两个或多个任务可以在重叠的时间段内启动、运行和完成。这并不一定意味着它们会在同一时刻运行。例如,在单核计算机上进行多任务处理。
并行性是指任务实际上同时运行,例如,在多核处理器上。
引用 Sun 的多线程编程指南:
并发性:当至少两个线程正在取得进展时存在的条件。一种更通用的并行形式,可以包括时间切片作为虚拟并行的一种形式。
并行性:当至少两个线程同时执行时出现的情况。
评论
他们解决不同的问题。并发解决了CPU资源稀缺、任务多的问题。因此,您可以通过代码创建线程或独立的执行路径,以便在稀缺资源上共享时间。直到最近,由于 CPU 可用性,并发性一直主导着讨论。
并行性解决了找到足够多的任务和适当的任务(可以正确拆分的任务)并将它们分布在充足的 CPU 资源上的问题。当然,并行性一直存在,但它正在走在最前沿,因为多核处理器非常便宜。
并发:如果两个或多个问题由单个处理器解决。
排比:如果一个问题由多个处理器解决。
评论
我喜欢 Rob Pike 的演讲:并发不是并行(更好!(幻灯片) (讨论)
Rob 通常谈论 Go,并且通常以直观和直观的解释来解决并发与并行的问题!以下是简短的总结:
任务:让我们烧掉一堆过时的语言手册!一次一个!
并发:任务有很多同时分解!举个例子:
排比:如果至少有 2 个地鼠同时工作,则前面的配置会并行发生。
评论
补充一下其他人所说的话:
并发就像让一个杂耍者玩弄许多球。不管看起来如何,杂耍者一次只抓/扔一个球。并行性是让多个杂耍者同时玩杂耍球。
评论
并发 => 当使用共享资源在重叠的时间段内执行多个任务时(可能最大限度地提高资源利用率)。
并行=>当单个任务被分成多个可以同时执行的简单独立子任务时。
评论
在电子学中,串行和并行代表一种静态拓扑结构,决定了电路的实际行为。当没有并发性时,并行性是确定性的。
为了描述动态的、与时间相关的现象,我们使用术语“顺序”和“并发”。例如,可以通过特定的任务序列(例如配方)获得某种结果。当我们与某人交谈时,我们正在产生一系列单词。然而,在现实中,许多其他过程在同一时刻发生,因此与某个动作的实际结果一致。如果很多人同时说话,并发通话可能会干扰我们的顺序,但这种干扰的结果事先是未知的。并发性引入了不确定性。
串行/并行和顺序/并发表征是正交的。这方面的一个例子是数字通信。在串行适配器中,数字消息在时间上(即顺序)沿同一通信线路(例如一根线)分布。在并联适配器中,这也在平行通信线路(例如许多电线)上被分割,然后在接收端重建。
让我们想象一个有 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 台服务器,1 个作业队列(有 5 个作业) -> 无并发性,无并行性(只有一个作业正在完成,队列中的下一个作业必须等到服务作业完成,并且没有其他服务器来服务它)
1 台服务器,2 个或更多不同的队列(每个队列有 5 个作业)->并发性(因为服务器与队列中的所有第一个作业共享时间,平均或加权),仍然没有并行性,因为在任何时刻,都有一个且唯一的作业正在服务。
2 个或更多服务器,一个队列 -> 并行性(同时完成 2 个作业),但没有并发性(服务器不共享时间,第三个作业必须等到其中一个服务器完成。
2 个或更多服务器,2 个或更多不同的队列 - >并发性和并行性
换句话说,并发是共享时间来完成一项工作,它可能占用相同的时间来完成其工作,但至少它很早就开始了。重要的是,作业可以分割成更小的作业,从而允许交错。
并行性是通过更多的CPU、服务器、人员等并行运行来实现的。
请记住,如果资源是共享的,则无法实现纯粹的并行性,但这是并发性的最佳实际用途,它承担了另一个不需要该资源的工作。
评论
太好了,让我举一个场景来展示我的理解。 假设有 3 个孩子被命名为:A、B、C。A和B说话,C听。 对于 A 和 B,它们是平行的: 答:我是A。 B:我是B。
但对于 C 来说,他的大脑必须同时听 A 和 B 的声音,这也许是: 我是我,我是 A,是 B。
我将提供一个与这里一些流行的答案有点冲突的答案。在我看来,并发性是一个通用术语,包括并行性。并发性适用于不同任务或工作单元在时间上重叠的任何情况。并行性更具体地适用于在同一物理时间评估/执行不同工作单元的情况。并行性存在的理由是加速可以从多种物理计算资源中受益的软件。另一个适合并发性的主要概念是交互性。当从外部世界可以观察到任务的重叠时,交互性适用。交互性的存在的理由是使软件能够响应现实世界的实体,如用户、网络对等方、硬件外围设备等。
并行性和交互性几乎是并发性几乎完全独立的维度。对于特定项目,开发人员可能关心其中之一,两者兼而有之,或者两者都不关心。它们往往会混为一谈,尤其是因为线程这个可憎的东西提供了一个相当方便的原语来做这两件事。
关于并行性的更多细节:
并行性存在于非常小的规模(例如处理器中的指令级并行性)、中等规模(例如多核处理器)和大规模(例如高性能计算集群)中。近年来,由于多核处理器的发展,软件开发人员公开更多线程级并行性的压力越来越大。并行性与依赖性的概念密切相关。依赖性限制了并行性的实现程度;如果一个任务依赖于另一个任务,则两个任务不能并行执行(忽略推测)。
程序员使用许多模式和框架来表达并行性:管道、任务池、数据结构上的聚合操作(“并行数组”)。
关于交互性的更多细节:
进行交互的最基本和最常见的方法是使用事件(即事件循环和处理程序/回调)。对于简单的任务,事件很棒。尝试使用事件执行更复杂的任务会进入堆栈翻录(又称回调地狱;又称控制反转)。当你厌倦了事件时,你可以尝试更奇特的东西,比如生成器、协程(又名 Async/Await)或协作线程。
出于对可靠软件的热爱,如果您追求的是交互性,请不要使用线程。
Curmudgeonliness
我不喜欢 Rob Pike 的“并发不是并行;It's Better“的口号。并发性既不比并行性好,也不比并行性差。并发性包括交互性,它不能以更好/更差的方式与并行性进行比较。这就像说“控制流比数据更好”。
为什么存在混乱
之所以存在混淆,是因为这两个词的字典含义几乎相同:
- 并发:同时存在、正在发生或完成 (dictionary.com)
- 平行:非常相似,经常同时发生(梅里亚姆·韦伯斯特)。
然而,它们在计算机科学和编程中的使用方式却大不相同。以下是我的解释:
- 并发性:可中断性
- 并行性:独立性
那么我所说的上述定义是什么意思呢?
我将用现实世界的类比来澄清。假设您必须在一天内完成 2 项非常重要的任务:
- 获取护照
- 完成演示文稿
现在,问题是任务 1 要求你去一个非常官僚的政府办公室,让你排队等 4 个小时才能拿到护照。同时,您的办公室需要任务 2,这是一项关键任务。两者都必须在特定日期完成。
案例 1:顺序执行
通常,您将开车到护照办公室 2 小时,排队等候 4 小时,完成任务,开车返回 2 小时,回家,再保持清醒 5 小时并完成演示。
案例 2:并发执行
但你很聪明。你提前计划。你随身携带一台笔记本电脑,在排队等候时,你开始处理你的演示文稿。这样,一旦你回到家,你只需要多工作 1 小时而不是 5 小时。
在这种情况下,这两项任务都是由您完成的,只是分段完成。您在排队等候时中断了护照任务,并着手演示。当您的号码被叫到时,您中断了演示任务并切换到护照任务。由于这两项任务的可中断性,基本上可以节省时间。
并发性,IMO,可以理解为 ACID 中的“隔离”属性。如果子事务可以以任何交错方式执行,并且最终结果与按顺序完成这两个任务相同,则认为两个数据库事务是隔离的。请记住,对于护照和演示任务,您都是唯一的刽子手。
案例 3:并行执行
现在,既然你是一个聪明的家伙,你显然是一个更高的人,而且你有一个助手。所以,在你离开开始护照任务之前,你打电话给他,告诉他准备演示文稿的初稿。你花了一整天的时间完成护照任务,回来看看你的邮件,然后你找到了演示草稿。他做得相当扎实,在 2 小时内进行了一些编辑,您就完成了它。
现在,由于你的助手和你一样聪明,他能够独立工作,而不需要经常要求你澄清。因此,由于任务的独立性,它们由两个不同的刽子手同时执行。
还在我身边吗?好。。。
案例 4:并发但不并行
还记得你的护照任务,你必须排队等候吗? 由于这是您的护照,您的助理不能排队等候您。因此,护照任务具有可中断性(您可以在排队等候时停止它,并在稍后呼叫您的号码时恢复它),但没有独立性(您的助手不能代替您等待)。
案例 5:并行但非并发
假设政府办公室有安全检查才能进入场所。在这里,您必须移除所有电子设备并将其提交给官员,他们只会在您完成任务后归还您的设备。
在这种情况下,护照任务既不可独立,也不可中断。即使您在排队等候,您也无法从事其他工作,因为您没有必要的设备。
同样,假设演示文稿本质上是高度数学化的,以至于您需要 100% 的注意力至少 5 小时。即使您随身携带笔记本电脑,您也无法在排队等候护照任务时这样做。
在这种情况下,演示任务是独立的(您或您的助手可以投入 5 小时的专注精力),但不可中断。
案例 6:并发和并行执行
现在,假设除了指派您的助手进行演示外,您还随身携带一台笔记本电脑来执行护照任务。在排队等候时,您会看到您的助手已在共享幻灯片组中创建了前 10 张幻灯片。你对他的工作发表评论,并进行了一些更正。后来,当你回到家时,你只需要 15 分钟,而不是 2 个小时来完成草稿。
这是可能的,因为演示任务具有独立性(你们中的任何一个都可以做到)和可中断性(您可以停止它并稍后恢复它)。因此,您同时执行了这两个任务,并并行执行了演示任务。
比方说,除了过于官僚主义之外,政府办公室还腐败。因此,您可以出示您的身份证明,输入它,开始排队等待您的号码被呼叫,贿赂警卫和其他人以保持您在队列中的位置,偷偷溜出去,在您的号码被呼叫之前回来,然后继续等待自己。
在这种情况下,您可以同时并行执行护照和演示任务。你可以偷偷溜出去,你的位置由你的助手担任。然后你们俩都可以处理演示文稿等。
回到计算机科学
在计算领域,以下是每种情况的典型示例场景:
- 案例一:中断处理。
- 案例二:当只有一个处理器,但由于 I/O 的原因,所有正在执行的任务都有等待时间时。
- 案例三:当我们谈论map-reduce或hadoop集群时经常看到。
- 案例四:我认为案例 4 很少见。任务是并发的但不并行的情况并不常见。但它可能会发生。例如,假设您的任务需要访问一个特殊的计算芯片,该芯片只能通过处理器 1 访问。因此,即使处理器 2 是空闲的,并且处理器 1 正在执行其他任务,特殊计算任务也无法在处理器 2 上继续进行。
- 案例 5:也很少见,但不像案例 4 那么罕见。非并发代码可以是受互斥锁保护的关键区域。一旦启动,它必须执行到完成。但是,两个不同的关键区域可以在两个不同的处理器上同时进行。
- 案例6:IMO,大多数关于并行或并发编程的讨论基本上都在谈论案例 6。这是并行和并发执行的混合和匹配。
并发和 Go
如果你明白为什么 Rob Pike 说并发更好,你必须明白原因是什么。您有一个非常长的任务,其中有多个等待期,您可以在其中等待一些外部操作,例如文件读取、网络下载。在他的演讲中,他只想说,“只要打破这个漫长的顺序任务,这样你就可以在等待时做一些有用的事情。这就是为什么他谈论不同的组织与不同的地鼠。
现在,Go 的优势在于通过关键字和渠道使这种突破变得非常容易。此外,运行时中还有出色的底层支持来调度这些 goroutines。go
但从本质上讲,并发性比并行性好吗?
苹果比橙子好吗?
评论
并发简单意味着多个任务正在运行(不需要并行运行)。例如,假设我们有 3 个任务,然后在任何时刻:可能有多个任务正在运行,或者所有任务可能同时运行。
并行性意味着它们实际上是并行运行的。因此,在这种情况下,这三个必须同时运行。
简单示例:
并发是:“两个队列访问一台ATM机”
并行是:“两个队列和两台ATM机”
评论
我将尝试用一个有趣且易于理解的例子来解释。:)
假设一个组织组织了一场国际象棋锦标赛,其中 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=2 分钟)
假设所有玩家都需要 45 秒才能完成他们的回合,那么根据 SERIAL 事件的每场比赛 10 分钟,没有。比赛结束前的回合数应为 600/(45+6) = 11 回合(大约)
因此,整个事件大约在 11xtime_per_turn_by_player_&_champion + 11xtransition_time_across_10_players = 11x51 + 11x60 秒 = 561 + 660 = 1221 秒 = 20.35 分钟(大约)内完成
查看从 101 分钟到 20.35 分钟的改进(更好的方法)
3) 平行 - 假设组织者获得了一些额外的资金,因此决定邀请两名职业冠军选手(能力相同),并将相同的 10 名选手(挑战者)分成两组,每组 5 人,并将他们分配给两个冠军,即每组一组。现在,该赛事在这两组比赛中并行进行,即至少有两名球员(每组一名)与各自小组中的两名职业球员进行比赛。
然而,在小组内,职业选手一次(即按顺序)带走一名球员,因此无需任何计算,您就可以很容易地推断出整个事件大约将在 101/2=50.5 分钟内完成
查看从 101 分钟到 50.5 分钟的改进(好方法)
4) 并发 + 并行 - 在上面的场景中,假设两名冠军玩家将与各自组中的 5 名玩家同时进行(阅读第 2 点),因此现在跨组的游戏是并行运行的,但在组内,它们是同时运行的。
因此,一组中的游戏将在 11xtime_per_turn_by_player_&_champion + 11xtransition_time_across_5_players = 11x51 + 11x30 = 600 + 330 = 930 秒 = 15.5 分钟(大约)内完成
因此,整个事件(涉及两个这样的并行运行组)将在 15.5 分钟内完成
查看从 101 分钟到 15.5 分钟的改进(最佳方法))
注意:在上述场景中,如果您将 10 名具有 10 个类似职业的玩家替换为 2 个具有两个 CPU 内核的职业玩家,则以下顺序将保持不变:
串行>并行>并发>并发+并行
(注意:对于其他方案,此顺序可能会更改,因为此顺序在很大程度上取决于作业的相互依赖性、作业之间的通信需求以及作业之间的转换开销)
评论
假设您有一个有两个线程的程序。该程序可以通过两种方式运行:
Concurrency Concurrency + parallelism
(Single-Core CPU) (Multi-Core CPU)
___ ___ ___
|th1| |th1|th2|
| | | |___|
|___|___ | |___
|th2| |___|th2|
___|___| ___|___|
|th1| |th1|
|___|___ | |___
|th2| | |th2|
在这两种情况下,我们都有并发性,因为我们有多个线程在运行。
如果我们在具有单个 CPU 内核的计算机上运行此程序,操作系统将在两个线程之间切换,允许一次运行一个线程。
如果我们在具有多核 CPU 的计算机上运行此程序,那么我们将能够并行运行两个线程 - 同时并排运行。
评论
并发性是并行性的广义形式。例如,并行程序也可以称为并发程序,但反向程序不是真的。
可以在单个处理器上并发执行(多个线程,由调度程序或线程池管理)
并行执行不能在单个处理器上执行,而是在多个处理器上执行。(每个处理器一个进程)
分布式计算也是一个相关的主题,它也可以称为并发计算,但反向计算并非如此,就像并行一样。
有关详细信息,请阅读这篇研究论文:并发编程的概念
Pike 的“并发性”概念是一个有意的设计和实现决策。具有并发功能的程序设计可能会也可能不会表现出行为上的“并行性”;这取决于运行时环境。
您不希望不是为并发而设计的程序表现出并行性。:-)但是,在某种程度上,它是相关因素(功耗、性能等)的净收益,您需要最大并发设计,以便主机系统可以在可能的情况下并行执行。
Pike 的 Go 编程语言在极端情况下说明了这一点:他的函数都是可以并发正确运行的线程,即调用函数总是创建一个线程,如果系统能够这样做,该线程将与调用者并行运行。一个拥有数百甚至数千个线程的应用程序在他的世界里是完全普通的。(我不是围棋专家,这只是我的看法。
只要查字典,你就可以看出,concurrent(来自拉丁语)的意思是一起奔跑、收敛、同意;因此,需要同步,因为存在对相同资源的竞争。平行(来自希腊语)的意思是在侧面复制;因此,可以同时做同样的事情。
评论
我真的很喜欢 Paul Butcher 对这个问题的回答(他是 Seven Concurrency Models in Seven Weeks 的作者):
尽管它们经常被混淆,但并行性和并发性是 不同的东西。并发性是问题域的一个方面 - 你的 代码需要同时处理多个(或几乎同时处理) 事件。相比之下,并行性是解决方案的一个方面 域 - 您希望通过处理来加快程序的运行速度 问题的不同部分并行。一些方法是 适用于并发,有些适用于并行,有些适用于两者。 了解您面临的问题,并为 工作。
并发性可以涉及任务同时运行或不同时运行(它们确实可以在单独的处理器/内核中运行,但它们也可以在“滴答声”中运行)。重要的是,并发性总是指完成一项更大的任务。所以基本上它是一些计算的一部分。你必须聪明地知道你可以同时做什么,不能做什么以及如何同步。
并行性意味着你只是同时做一些事情。他们不需要成为解决一个问题的一部分。例如,您的线程可以解决每个线程的单个问题。当然,同步的东西也适用,但从不同的角度来看。
想象一下,通过观看视频教程来学习一种新的编程语言。您需要暂停视频,应用代码中所说的内容,然后继续观看。这就是并发性。
现在你是一名专业的程序员。您喜欢在编码时听平静的音乐。这就是并行性。
正如 Andrew Gerrand 在 GoLang 博客中所说
并发是指同时处理很多事情。排比 就是一次做很多事情。
享受。
排比:让多个线程执行类似的任务,这些任务在执行任务所需的数据和资源方面彼此独立。例如:谷歌爬虫可以生成数千个线程,每个线程都可以独立完成任务。
并发:当您在线程之间共享数据、共享资源时,并发性就会出现。在事务系统中,这意味着您必须使用一些技术(如锁、信号量等)来同步代码的关键部分。
评论
并发编程涉及看似重叠的操作,主要关注由于非确定性控制流而产生的复杂性。与并发程序相关的定量成本通常包括吞吐量和延迟。并发程序通常受 IO 限制,但并非总是如此,例如,并发垃圾收集器完全在 CPU 上。并发程序的教学示例是网络爬虫。该程序发起对网页的请求,并在下载结果可用时同时接受响应,从而累积一组已访问的页面。控制流是不确定的,因为每次运行程序时,响应不一定以相同的顺序接收。此特性可能使调试并发程序变得非常困难。一些应用程序基本上是并发的,例如 Web 服务器必须并发处理客户端连接。Erlang 可能是最有前途的高并发编程语言。
并行编程涉及为提高吞吐量的特定目标而重叠的操作。通过使控制流具有确定性,避免了并发编程的困难。通常,程序会生成一组并行运行的子任务,并且父任务仅在每个子任务完成后才继续。这使得并行程序更易于调试。并行编程的难点是针对粒度和通信等问题进行性能优化。后者在多核环境中仍然是一个问题,因为将数据从一个缓存传输到另一个缓存会产生相当大的成本。密集矩阵-矩阵乘法是并行规划的一个教学示例,通过使用 Straasen 的分而治之算法并行解决子问题可以有效地解决它。Cilk 可能是在共享内存计算机(包括多核)上进行高性能并行编程的最有前途的语言。
从我的答案中复制:https://stackoverflow.com/a/3982782
这个来源的解释对我很有帮助:
并发性与应用程序处理多个任务的方式有关 继续工作。一个应用程序一次可以处理一个任务 (按顺序)或同时处理多个任务 (同时)。
另一方面,并行性与应用程序的方式有关 处理每个单独的任务。应用程序可以处理该任务 从头到尾连续,或将任务拆分为子任务,这些子任务 可以并行完成。
如您所见,应用程序可以是并发的,但不能并行。 这意味着它同时处理多个任务,但 这些任务不会分解为子任务。
应用程序也可以是并行的,但不能并发。这意味着 应用程序一次只处理一个任务,并且此任务 被分解为可以并行处理的子任务。
此外,应用程序既不能是并发的,也可以是并行的。 这意味着它一次只处理一个任务,并且该任务是 从不分解为子任务以供并行执行。
最后,应用程序也可以是并发的和并行的,在 它既可以同时处理多个任务,又会中断 每个任务都分解为子任务以供并行执行。但是,一些 并发性和并行性的好处可能会因此而丢失 场景,因为计算机中的 CPU 已经保持相当繁忙的状态 仅具有并发性或并行性。结合它可能会导致 只有很小的性能提升甚至性能损失。
评论
“并发性”是指有多个事情正在进行中。
“并行性”是指并发的事情同时进行。
没有并行性的并发示例:
但请注意,并发性和并行性之间的区别通常是一个视角问题。从执行代码的角度来看,上述示例是非并行的。但是,即使在单个内核中也存在指令级并行性。有些硬件与 CPU 并行执行操作,然后在完成后中断 CPU。在执行窗口过程或事件处理程序时,GPU 可能会绘制到屏幕。DBMS 可能会在下一个查询中遍历 B 树,而您仍在获取上一个查询的结果。浏览器可能在执行时正在进行布局或网络。等等,等等......Promise.resolve()
所以你去吧。世界一如既往地混乱;)
评论
在我看来,理解两者最简单、最优雅的方式是这样的。并发性允许执行的交错,因此会给人一种并行性的错觉。例如,这意味着并发系统可以在您在 Word 中编写文档的同时运行您的 Youtube 视频。底层操作系统是一个并发系统,使这些任务能够交错执行。由于计算机执行指令的速度如此之快,这给人一种同时做两件事的感觉。
并行性是指这些事情真正并行。在上面的示例中,您可能会发现视频处理代码在单个内核上执行,而 Word 应用程序在另一个内核上运行。请注意,这意味着并发程序也可以并行!使用线程和进程构建应用程序使程序能够利用底层硬件,并可能并行完成。
那为什么不让一切都是平行的呢?原因之一是并发性是构建程序的一种方式,并且是促进关注点分离的设计决策,而并行性通常以性能的名义使用。另一个是,有些事情从根本上不能完全并行完成。例如,在队列的后面添加两个内容 - 您不能同时插入两个内容。有些东西必须先走,另一个在它后面,否则你就会搞砸队列。尽管我们可以交错执行这样的执行(因此我们得到了一个并发队列),但你不能让它并行。
希望这有帮助!
我真的很喜欢另一个答案中的图形表示 - 我认为它比上面的许多答案更好地回答了这个问题
并行性与并发性当两个线程并行运行时,它们都同时运行。例如,如果我们有两个线程,A 和 B,那么它们的并行执行将如下所示:
CPU 1:------------------------->
CPU 2:B ------------------------->
当两个线程同时运行时,它们的执行会重叠。重叠可以通过以下两种方式之一发生:线程同时执行(即并行执行,如上所述),或者它们的执行在处理器上交错执行,如下所示:
CPU 1:A -----------> B ----------> A -----------> B ---------->
因此,就我们的目的而言,并行性可以被认为是并发性的一种特殊情况
来源:另一个答案在这里
希望能有所帮助。
(我很惊讶这样一个基本问题多年来一直没有得到正确和整齐的解决......
简而言之,并发性和并行性都是计算的属性。
至于区别,以下是罗伯特·哈珀(Robert Harper)的解释:
首先要明白的是,并行性与并发性无关。并发性涉及程序(或其组件)的非确定性组合。并行性关注具有确定性行为的程序的渐近效率。并发就是管理不可控的:事件的出现超出了我们的控制范围,我们必须对它们做出响应。用户单击鼠标时,窗口管理器必须做出响应,即使显示需要注意。这种情况本质上是非确定性的,但我们也在确定性环境中采用形式非确定性,假装组件以任意顺序发出事件信号,并且我们必须在它们出现时做出反应。非确定性组合是一个强大的程序结构思想。另一方面,并行性是关于确定性计算的子计算之间的依赖关系。结果是毋庸置疑的,但实现它的方法有很多,有些比其他方法更有效。我们希望利用这些机会为我们谋取利益。
它们可以是程序中的某种正交属性。阅读这篇博文,了解其他插图。这篇论文稍微讨论了编程中组件(如线程)的差异。
请注意,线程或多任务处理都是用于更具体目的的计算实现。它们可以与并行性和并发性相关,但不是以本质的方式。因此,它们几乎不是开始解释的好条目。
还有一点是:(物理)“时间”与这里讨论的属性几乎没有关系。时间只是一种实现测量的方式,以显示属性的意义,但远非本质。三思而后行 “时间”在时间复杂度中的作用 - 这或多或少是相似的,在这种情况下,即使测量通常更重要。
并行性是指在 或 上同时执行进程。multiple cores per CPU
multiple CPUs (on a single motherboard)
并发是指通过使用划分 CPU 时间(时间片)的调度算法在 a 上实现并行性。进程是交错的。single core/CPU
单位:
- 单个 CPU 中有 1 个或多个内核(几乎所有现代处理器)
- 主板上有 1 个或多个 CPU(想想老式服务器)
- 1 个应用程序就是 1 个程序(想想 Chrome 浏览器)
- 一个程序可以有 1 个或多个进程(认为每个 Chrome 浏览器标签页都是一个进程)
- 1 个进程可以有来自 1 个程序的 1 个或多个线程(Chrome 选项卡在 1 个线程中播放 Youtube 视频,另一个线程生成评论 部分,另一个用于用户登录信息)
- 因此,一个程序可以有 1 个或多个执行线程
- 1 个进程是(堆、寄存器、堆栈、类内存)
thread(s)+allocated memory resources by OS
评论
并发编程执行有2种类型:非并行并发编程和并行并发编程(也称为并行)。
关键的区别在于,在人眼看来,非并发线程似乎同时运行,但实际上并非如此。在非并行并发中,线程通过时间切片快速切换并轮流使用处理器。 虽然在并行中,有多个处理器可用,但多个线程可以同时在不同的处理器上运行。
参考:编程语言中的并发性简介
评论
“并发”是同时做任何事情。它们可能是不同的东西,也可能是同一件事。尽管缺乏公认的答案,但这并不是关于“看起来同时存在”。这真的是同时进行的。您需要多个 CPU 内核,要么使用一台主机内的共享内存,要么使用不同主机上的分布式内存,才能运行并发代码。例如,同时运行的 3 个不同任务的管道:任务级别 2 必须等待任务级别 1 完成的单元,任务级别 3 必须等待任务级别 2 完成的工作单元。另一个例子是 1 个生产者与 1 个消费者的并发性;或多生产者和 1 消费者;读者和作家;等。
“并行”是同时做同样的事情。它是并发的,但除此之外,它是同时发生的相同行为,并且通常发生在不同的数据上。矩阵代数通常可以并行化,因为重复运行相同的操作:例如,矩阵的列总和都可以使用相同的行为(总和)同时计算,但在不同的列上。在可用处理器内核之间对列进行分区(拆分)是一种常见的策略,以便每个处理器内核处理的工作量(列数)接近相同。另一种拆分工作的方法是任务包,完成工作的员工回到经理那里,经理分发工作并动态地获得更多工作,直到所有事情都完成。票务算法是另一种。
不仅仅是数字代码可以并行化。文件经常可以并行处理。在自然语言处理应用程序中,对于数百万个文档文件中的每一个文件,您可能需要计算文档中的标记数。这是并行的,因为您正在对每个文件进行令牌计数,这是相同的行为。
换言之,并行性是指同时执行相同的行为。同时意味着同时,但不一定是相同的行为。并行是一种特殊的并发性,其中同样的事情同时发生。
例如,术语将包括原子指令、关键部分、互斥、自旋等待、信号量、监视器、障碍、消息传递、map-reduce、心跳、环、票务算法、线程、MPI、OpenMP。
Gregory Andrews 的著作是这方面的顶级教科书:多线程、并行和分布式编程。
评论
摘自这篇精彩的博客:
并发性和并行性之间的区别:
并发是指两个任务可以在 重叠的时间段。并行性是指任务实际上在 同时,例如。在多核处理器上。
并发是独立执行的进程的组成, 而并行性是同时执行(可能相关) 计算。
并发是指同时处理很多事情。排比 就是一次做很多事情。
应用程序可以是并发的,但不能并行,这意味着 它同时处理多个任务,但没有两个任务 同时即时执行。
应用程序可以是并行的,但不能并发,这意味着 它同时在多核 CPU 中处理任务的多个子任务 时间。
应用程序既不能并行,也不能并发,这意味着 它按顺序一次处理一个任务。
应用程序既可以是并行的,也可以是并发的,这意味着 它同时在多核 CPU 中同时处理多个任务 时间。
评论
简单地说,并发就是同时处理很多事情。
“dealing”一词是粗体字,用于表示并发性和并行性之间的区别。一次处理很多事情意味着一次完成很多事情,但它们是否同时执行并不重要。另一方面,并行意味着同时做很多事情(同时执行)。因此,可以使用一个或多个处理资源实现并发上下文。使用一个处理资源同时处理许多事情意味着您正在执行许多事情,因为它们是通过在任务之间进行上下文切换来同时执行的。另一方面,具有许多处理资源的并发上下文意味着执行并行性。这意味着我们通过并行来实现并发性,但反之亦然。
在我的文章中,您可能想了解更多关于并发性和并行性以及它们与当今技术的关系的信息。
只是为了给其他好的答案添加更多的澄清:
基于处理的抽象(CPU 是一个非常可以想象的例子)能够在同一时刻运行唯一任务的前提,
并发性是一个关于处理非常抽象的故事:它可以在不同的任务之间切换。
并行性是一个关于我们有不止一个处理抽象的故事(例如,我们的 CPU 有多个内核)。因此,这就是我们系统能够同时执行多项任务的原因(从字面上看)。但是这里没有提到处理的特定抽象(它们是否并发)。
这里的重点是这些故事是关于什么的。
因此,当您阅读公认的答案时,请注意:
并发是指两个或多个任务可以在 重叠的时间段。
严格地说,根据这个定义,我们可以得出结论,并行性本身是以并发性为前提的。
摘自 Robert Love 的《Linux 系统编程》一书:
并发性、并行性和竞争
线程会产生两种相关但截然不同的现象:并发和 排比。两者都是苦乐参半的,涉及穿线成本 以及它的好处。并发性是指两个或多个的能力 在重叠的时间段内执行的线程。并行性是 同时执行两个或多个线程的能力。 并发可以在没有并行性的情况下发生:例如,多任务处理 在单处理器系统上。并行性(有时强调为真正的并行性)是一种特定的并发形式,需要多个处理器(或能够运行多个引擎的单个处理器) 的执行,例如 GPU)。通过并发,多个线程使 向前推进,但不一定同时进行。跟 并行性,线程实际上是并行执行的,允许 利用多个处理器的多线程程序。
并发是一种编程模式,一种解决问题的方式。 并行性是一种硬件功能,可通过并发实现。 两者都很有用。
这种解释与公认的答案是一致的。实际上,这些概念比我们想象的要简单得多。不要认为它们是魔法。并发性大约是一段时间,而并行性大约是在同一时间同时进行的。
并发性与并行性
Rob Pike 在《并发不是并行》中
并发是指同时处理很多事情。
并行性是指同时做很多事情。
并发 - 一次处理多个任务 并行性 - 一次
处理多个线程
我对并发和并行性的看法
评论
如果有的话,你想向一个 9 岁的孩子解释这一点。
我认为由于对这个问题的两种不同观点存在混淆:程序员的观点(并发/并行编程)与计算机/操作系统的观点(并发/并行执行)。
这里回答了计算机的观点。
程序员的观点:
并发编程:程序员编写代码时知道代码将由多个线程执行,无论出于何种原因。原因可能是:在等待 I/O 时更好地利用 CPU,通过不同的线程处理 Web 请求,通过在与主线程分开的线程中运行计算来使 GUI 响应,定期运行后台任务。 程序员必须应用互斥结构、锁定/解锁、等待条件/信号、处理死锁等。多个线程可以在单个处理器/内核上运行(从计算机的角度来看是并发的),也可以在多个内核上运行(从计算机的角度来看是并行的)。
并行编程:程序员知道程序将在具有多个处理器/内核的计算机上运行,并希望利用多个内核。程序员将 CPU 密集型计算划分为多个子任务,在线程中运行每个子任务,一旦线程完成,它们的结果就会组合成总结果(分而治之)。例如,将一些矩阵处理代码划分为并行处理矩阵各部分的任务。每个核心将 使用子任务执行一个线程(如果线程数大于内核数,则同时执行多个线程)。程序员也必须在这里应用并发的编程结构,但她也关心将任务划分为子任务并组合结果。例如,在 Java 中,程序员可以使用 ParallelStreams 来拆分数据并自动组合结果。如果程序员知道程序将在单核处理器上执行,那么将 CPU 密集型任务拆分为多个线程是没有好处的。摘自 Concurrent Programming in Java : Design Principles and Patterns, 2nd Edition, 1999, by Doug Leah, page 343:
并行程序专门设计用于利用多个 CPU 来解决计算密集型问题。
并发是编程术语。它是关于多个任务,这些任务以无特定顺序在重叠的时间段内开始运行和完成。并发由操作系统管理。当多个线程想要访问同一资源时,线程会出现争用条件问题。此外,他们也有死锁,他们互相等待,阻止自己奔跑。 例如,你想边吃饭边说话。首先你需要吞下嘴里的食物或停止咀嚼,然后你才能说话(你正在旋转线程),说话后你可以再咬一口。
并行性是一个硬件术语。它是关于在具有多个计算资源(如多核处理器)的硬件上同时运行的多个任务。如果你能在咀嚼食物时说话,这将是平行的。平行的一个例子是,一个人可以同时唱歌和跳舞。
并发
Rob Pike 在他的 Concurrency Is Not Parallelism 演讲中将并发定义为同时处理很多事情。
例如,在单个 CPU 上执行三个任务¹ T1、T2 和 T3。
在每个时间点(如绿色垂直线所示),CPU 运行单个任务,即 T1 运行一个位,然后是 T2,然后是 T1,然后是 T3,依此类推。然而,任务之间的上下文切换发生得如此之快,以至于对于人类观察者来说,似乎 CPU 正在同时执行这三个任务。实际上,任务正在取得进展(如灰色水平线所示),即使在任何给定时间点 CPU 都在执行单个任务。所有任务执行都是交错的,因此是并发执行的。在现代操作系统(3E)中,Tanenbaum将其称为伪并行性。
现在,我们有三个任务被建模为在单个 CPU 上并发运行。如果我们有三个 CPU 内核而不是一个,会发生什么?这就是并行性的用武之地。
排比
Pike 将并行性定义为同时做很多事情。并行性是并发性的一个子集,它由硬件实现,其中不仅所有任务都在取得进展,而且它们同时在进行。
例如,如果我们有三个 CPU 内核,并将之前的每个任务放在一个单独的 CPU 内核上,那么它们将相互并行执行。
每个 CPU 内核都在执行一个任务,并且一直在继续执行它,而无需上下文切换,因此所有三个任务实际上是同时执行的。当 T1 在做某事时,T2 和 T3 也在做某事。同样,T1、T2 和 T3 因此并行执行。
现在并发性和并行性不是相互排斥的,你也可以有并发性。
并行并发
并行并发正在多个 CPU 上完成多个任务(看似同时)。假设我们只有两个 CPU 内核,但任务数量与以前相同,那么一种可能的配置是两个任务在一个 CPU 内核上执行,另一个任务在另一个 CPU 内核上执行。
在此示例中,任务 T1 和 T3 在第一个 CPU 上彼此并发执行,而任务 T2 相对于 T1 或 T3 完全并行运行。为什么不是 T1 和 T3?因为第一个 CPU 在任何给定时间都在执行单个任务。因此,T2 在某个时间点与 T1 并行运行,然后 T2 与 T3 并行运行,依此类推。
总结
并发性是一次处理很多事情,并行性是同时做很多事情。
并行性是并发性的一个子集。如果任务未分解为在单个 CPU 上并发运行,则它们可能无法并行运行。即使有可用的硬件来启用它。
除非硬件启用,否则没有并行性。如果没有多个 CPU 内核,则无法并行化并发任务。
并发性和并行性并不相互排斥,它们也不需要存在。应用程序可以是
- 并发但不是并行的,例如,它被分解为并发任务,但只有一个 CPU。
- 并行但不是并发的,例如,任务数等于 CPU 内核数,因此每个任务彼此并行运行。
- 并发和并行,例如,它被分解为并发任务,但没有足够的 CPU 内核用于每个单独的任务。
- 既不是并发的,也不是并行的,例如,单个 CPU 内核,并且应用程序不会分解为单独的并发任务。
¹ 我使用“任务”一词来指代进程和线程。
评论