并行编程和并行编程的区别是什么?

并行编程和并行编程的区别是什么?我问了谷歌,但没有找到任何帮助我理解这种区别的东西。你能给我举个例子吗?

现在我发现这个解释:http://www.linux-mag.com/id/7411 -但“并发性是程序的属性”vs“并行执行是机器的属性”对我来说还不够-我仍然不能说什么是什么。

137423 次浏览

我认为并发编程指的是多线程编程,它是关于让你的程序运行多个线程,从硬件细节中抽象出来。

并行编程是指专门设计程序算法以利用可用的并行执行。例如,您可以并行执行某些算法的两个分支,期望它会比先检查第一个分支再检查第二个分支更快地到达结果(平均而言)。

它们是从(非常轻微的)不同的角度描述同一件事情的两个短语。并行编程是从硬件的角度描述情况——至少有两个处理器(可能在一个物理包中)并行处理一个问题。并发编程更多地是从软件的角度描述事情——两个或多个操作可能同时(并发)发生。

这里的问题是,人们试图用这两个短语来做出明确的区分,但实际上这两个短语并不存在。现实情况是,几十年来,他们试图划定的分界线一直是模糊的,而且随着时间的推移越来越模糊。

他们试图讨论的事实是,在过去,大多数计算机只有一个CPU。当你在同一个CPU上执行多个进程(或线程)时,CPU实际上一次只能执行来自其中一个线程的一条指令。并发的出现是一种错觉——CPU在不同线程执行指令之间切换的速度足够快,以至于在人类的感知中(对于任何小于100毫秒左右的东西来说都是瞬时的),它看起来就像同时在做很多事情。

与此形成鲜明对比的是具有多个CPU或多核CPU的计算机,因此机器正在同时执行来自多个线程和/或进程的指令;执行其中一个的代码不能/不会对执行另一个的代码产生任何影响。

现在的问题是:如此清晰的区别几乎从未存在过。计算机设计人员实际上相当聪明,所以他们很久以前就注意到(例如)当你需要从I/O设备(如磁盘)读取一些数据时,它需要时间(以CPU周期为单位)才能完成。他们不是让CPU空闲,而是想出了各种方法让一个进程/线程发出I/O请求,并让来自其他进程/线程的代码在I/O请求完成时在CPU上执行。

因此,早在多核cpu成为标准之前,我们就有多个线程并行进行操作。

不过,这只是冰山一角。几十年前,计算机开始提供另一种级别的并行性。同样,作为相当聪明的人,计算机设计师注意到,在很多情况下,他们的指令不会相互影响,因此可以同时执行来自同一流的多条指令。一个广为人知的早期例子是控制数据6600。1964年推出时,这是地球上速度最快的计算机(以相当大的差距)——许多相同的基本架构在今天仍在使用。它跟踪每条指令所使用的资源,并有一组执行单元,一旦它们所依赖的资源可用,就立即执行指令,非常类似于最新的英特尔/AMD处理器的设计。

但是(正如广告中经常说的那样)等等——这还不是全部。还有另一个设计元素让人更加困惑。它被赋予了相当多不同的名称(例如,“超线程”,“SMT”,“CMP”),但它们都指的是相同的基本思想:CPU可以同时执行多个线程,使用一些独立于每个线程的资源的组合,以及一些线程之间共享的资源。在典型的情况下,这与上面概述的指令级并行性相结合。为此,我们有两组(或更多)体系结构寄存器。然后,我们有一组执行单元,一旦必要的资源可用,就可以执行指令。它们通常结合得很好,因为来自不同流的指令实际上从不依赖于相同的资源。

然后,当然,我们会讲到具有多核的现代系统。这里的情况很明显,对吧?我们有N个(目前大约在2到256之间)独立的内核,它们都可以同时执行指令,所以我们有了真正的并行性的清晰案例——在一个进程/线程中执行指令不会影响在另一个进程/线程中执行指令。

嗯,算是吧。即使在这里,我们也有一些独立的资源(寄存器、执行单元、至少一个级别的缓存)和一些共享资源(通常至少是最低级别的缓存,当然还有内存控制器和内存带宽)。

总而言之:人们喜欢对比共享资源和独立资源的简单场景实际上从未在现实生活中发生过。在所有资源共享的情况下,我们最终得到了类似MS-DOS的东西,在那里我们一次只能运行一个程序,并且在运行另一个程序之前我们必须停止运行一个程序。对于完全独立的资源,我们有N台运行MS-DOS的计算机(甚至没有网络连接它们),它们之间根本无法共享任何东西(因为如果我们甚至可以共享一个文件,那么这就是共享资源,违反了不共享的基本前提)。

每个有趣的案例都涉及到独立资源和共享资源的某种组合。每一台相当现代的计算机(以及许多根本不现代的计算机)都至少有一些能力同时执行至少几个独立的操作,而任何比MS-DOS更复杂的东西都至少在某种程度上利用了这一点。

人们喜欢在“并发”和“并行”之间画出的漂亮、清晰的分界线根本不存在,而且几乎从来都不存在。人们喜欢归类为“并发”的东西通常仍然包含至少一种或更多不同类型的并行执行。他们喜欢归类为“并行”的内容通常涉及共享资源,(例如)一个进程在使用两个进程之间共享的资源时阻塞另一个进程的执行。

试图在“并行”和“并发”之间划清界限的人,其实是生活在一个从未真正存在过的计算机幻想中。

如果你的程序使用线程(并发编程),它不一定会这样执行(并行执行),因为这取决于机器是否可以处理几个线程。

这是一个直观的例子。的非机器上的线程:

        --  --  --
/              \
>---- --  --  --  -- ---->>

螺纹机器上的线程:

     ------
/      \
>-------------->>

虚线表示执行的代码。正如您所看到的,它们都分开并分别执行,但是线程机器可以同时执行几个单独的部分。

我的理解是:

1)并发-使用共享资源串联运行 2)使用不同资源并行运行

所以你可以让两件事情同时发生,即使它们在点(2)聚集在一起,或者两件事情在整个执行的操作中占用相同的储备(1)。

并发编程考虑的是看似重叠的操作,主要关注的是由于不确定的控制流而引起的复杂性。与并发程序相关的定量成本通常是吞吐量和延迟。并发程序通常受IO限制,但也不总是如此,例如并发垃圾收集器完全在cpu上。并行程序的教学示例是网络爬虫程序。该程序启动对网页的请求,并在下载结果可用时同时接受响应,积累一组已经访问过的页面。控制流是不确定的,因为每次运行程序时,响应不一定以相同的顺序接收。这个特性使得调试并发程序非常困难。一些应用程序基本上是并发的,例如web服务器必须并发地处理客户端连接。Erlang, f# 异步工作流和Scala的Akka库可能是最有希望实现高并发编程的方法。

多核编程是并行编程的一个特例。并行编程关注为提高吞吐量的特定目标而重叠的操作。通过使控制流确定,避免了并发编程的困难。通常,程序生成并行运行的子任务集,父任务只有在每个子任务完成后才继续运行。这使得并行程序比并发程序更容易调试。并行编程的难点在于性能优化,比如粒度和通信。在多核环境中,后者仍然是一个问题,因为将数据从一个缓存传输到另一个缓存需要相当大的成本。密集矩阵-矩阵乘法是并行规划的一个教学实例,它可以通过使用Straasen分治算法和并行求解子问题得到有效解决。Cilk可能是在多核上进行高性能并行编程最有前途的方法,它已经被英特尔的螺纹构建块和微软的任务并行库(在。net 4中)所采用。

我在一些博客上找到了这个内容。认为它是有用的和相关的。

并发性和并行性不是一回事。两个任务T1和T2是并发的,如果这两个任务的执行顺序不是预先确定的,

T1可以在T2之前执行并完成, T2可以在T1之前执行和完成, T1和T2可以在同一个时间实例中同时执行(并行性), T1和T2可以交替执行, ... 如果操作系统安排两个并发线程在一个单核非smt非cmp处理器上运行,您可能会得到并发性而不是并行性。并行在多核、多处理器或分布式系统上是可能的

并发性通常被认为是程序的一种属性,是一个比并行性更普遍的概念。

来源:https://blogs.oracle.com/yuanlin/entry/concurrency_vs_parallelism_concurrent_programming

虽然没有完成 就术语平行并发之间的区别达成一致, 许多作者做了以下区分:

  • 在并发计算中,一个程序可以在任意时刻执行多个任务。
  • 在并行计算中,一个程序是多个任务紧密合作的程序 .解决一个问题
所以并行程序是并发的,但是像多任务操作系统这样的程序也是并发的,即使它运行在一台带有 只有一个核心,因为多个任务可以在任何时刻进行

:并行编程介绍,彼得·帕切科

经典的任务调度可以是串行平行并发

  • Serial:任务必须以已知的欺骗顺序一个接一个地执行,否则将不起作用。很容易。

  • 平行:任务必须同时执行,否则将无法工作。

    • 任何任务的任何失败-功能上或时间上-都会导致整个系统的失败。
    • 所有的任务都必须有一个共同的可靠的时间观念。
      < br >

    尽量避免这样,否则到下午茶时间我们就会流泪了

  • Concurrent: we do not care。不过,我们并非粗心大意:我们已经分析过了,这无关紧要;因此,我们可以在任何时间使用任何可用的工具执行任何任务。快乐的日子。

通常,在已知事件发生时,可用的调度会发生变化,我们称之为状态变化。

人们通常认为这是关于软件的,但实际上这是一种早于计算机的系统设计概念;软件系统的吸收速度有点慢,甚至很少有软件语言试图解决这个问题。如果你感兴趣,你可以尝试查找transpter语言occam

简而言之,系统设计解决以下问题:

  • 动词——你在做什么(操作或算法)
  • 名词——对(数据或接口)进行操作的对象
  • 启动时,进度、状态改变
  • 是串行、并行还是并发
  • 地点——一旦你知道事情发生的时间,你就能说出事情可能发生的地点,而不是之前。
  • 为什么,这是正确的方法吗?是否有其他方法,更重要的是更好的方法?如果你不做会怎么样?

祝你好运。

在编程中,并发是独立的组合 执行进程,而并行是同时执行 计算的(可能相关的)。
- Andrew Gerrand -

并发是独立执行的组合 计算。并发性是构建软件的一种方式 作为一种编写与现实世界良好交互的干净代码的方式。 它不是并行性

并发不是并行,尽管它可以实现并行。如果 你只有一个处理器,你的程序仍然可以是并发的,但是 它不能平行。另一方面,一个写得很好的并发 程序可以在多处理器上并行有效地运行。那 财产可能很重要……
- Rob Pike -

为了理解其中的区别,我强烈建议你去看看Rob Pike(Golang的创作者之一)的视频。并发不是并行

将原问题解释为并行/并发计算而不是编程

并发计算两个计算都向前推进中相互独立。第二个计算不需要等到第一个计算完成后才能继续进行。但是,它并没有说明这是如何实现的机制。在单核设置中,需要挂起和线程之间的交替(也称为先发制人的多线程)。

并行计算两个计算同时进行中-字面上是同时。这对于单CPU来说是不可能的,而是需要多核设置。

图片来自article: “Node.js中的并行vs并发”

暂停和轮流相对于并行计算

并行编程发生在代码同时被执行并且每次执行都是相互独立的时候。因此,通常不会有关于共享变量之类的关注,因为那不太可能发生。

然而,并发编程是由共享变量的不同进程/线程执行的代码组成的,因此在并发编程中,我们必须建立某种规则来决定哪个进程/线程先执行,我们希望这样我们可以确保有一致性,我们可以确定会发生什么。如果没有控制,所有线程都在同一时间计算,并将数据存储在相同的变量上,我们怎么知道最终会发生什么?也许一个线程比另一个线程快,也许其中一个线程甚至在执行过程中停止,而另一个线程继续使用一个损坏的(尚未完全计算)变量进行不同的计算,这种可能性是无限的。在这种情况下,我们通常使用并发编程而不是并行编程。

https://joearms.github.io/published/2013-04-05-concurrent-and-parallel-programming.html

并发=两个队列和一台咖啡机。

并行=两个队列和两个咖啡机。

< img src = " https://joearms.github.io/images/con_and_par.jpg " / >

从处理器的角度来看,它可以用这张图片来描述

In the view from a processor, It can be describe by this pic .

在处理器视图中,可以用pic描述

  • Concurrent programming在一般意义上指的是我们定义的任务可以以任何顺序发生的环境。一个 任务可以发生在另一个任务之前或之后,并且部分或所有任务可以 同时进行的。李< / p > < / >

  • Parallel programming是特指并发任务在不同处理器上同时执行。因此,所有 并行编程是并发的,但不是所有的并发编程 李是平行的。< / p > < / >

来源:PThreads编程-更好的多处理POSIX标准,Buttlar, Farrell, Nichols

并发性和并行性

在单处理器上的多线程进程中,处理器可以在线程之间切换执行资源,从而产生并发执行

在共享内存多处理器环境中的同一个多线程进程中,进程中的每个线程可以同时在单独的处理器上运行,从而产生并行执行

当进程的线程数量与处理器数量相同或较少时,线程支持系统结合操作环境确保每个线程运行在不同的处理器上。

例如,在具有相同数量的线程和处理器的矩阵乘法中,每个线程(和每个处理器)计算结果的一行。

不同的人在许多不同的具体情况下讨论不同类型的并发性和并行性,因此需要一些抽象来涵盖它们的共同性质。

基本的抽象是在计算机科学中完成的,其中并发性和并行性都归因于程序的属性。在这里,程序是计算的形式化描述。这样的程序不需要使用任何特定的语言或编码,这是特定于实现的。API/ABI/ISA/OS的存在与这种抽象级别无关。当然,人们需要更详细的特定于实现的知识(比如线程模型)来进行具体的编程工作,基本抽象背后的精神没有改变。

第二个重要的事实是,作为一般属性,并发性和并行性可以在许多不同的抽象中共存

对于一般的区别,参见相关答案关于并发和并行的基本观点。(也有一些链接包含一些额外的来源。)

并发编程和并行编程是用一些系统实现这些一般属性的技术,这些系统公开了可编程性。系统通常是编程语言及其实现。

编程语言可以通过内置的语义规则公开预期的属性。在大多数情况下,这些规则指定了特定语言结构(例如表达式)的计算,使所涉及的计算有效地并发或并行。(更具体地说,由计算所隐含的计算效果可以完美地反映这些属性。)然而,并发/并行语言的语义本质上是复杂的,在实际工作中(实现高效的并发/并行算法作为现实问题的解决方案)并不需要它们。因此,大多数传统语言采取更保守和更简单的方法:假设计算的语义完全是顺序和串行的,然后提供可选的原语,以允许一些的计算是并发和并行的。这些原语可以是语言支持的关键字或过程结构(“函数”)。它们是基于与托管环境(OS,或“裸金属”硬件接口)的交互实现的,通常是不透明的(不能使用语言可移植地派生)。因此,在程序员所看到的这种特殊的高级抽象中,除了这些“神奇的”原语和依赖于这些原语的程序之外,没有什么是并发/并行的;这样,当并发/并行性属性不那么感兴趣时,程序员就可以享受更少容易出错的编程体验。

尽管在最高级别的抽象中,原语抽象了复杂性,但实现仍然具有语言特性没有暴露的额外复杂性。因此,需要一些中级抽象。一个典型的例子是线程。线程允许一个或多个执行线程(或简单地线程;有时它也被称为过程,这并不一定是在操作系统中计划的任务的概念),由语言实现(运行时)支持。线程通常由运行时预先调度,因此线程不需要知道其他线程的任何信息。因此,线程很自然地实现并行,只要它们不共享任何东西(关键资源):只要在不同的线程中分解计算,一旦底层实现允许在执行期间重叠计算资源,它就可以工作。线程还受到共享资源的并发访问:只需以满足算法要求的最小约束的任何顺序访问资源,最终由实现决定何时访问。在这种情况下,可能需要进行一些同步操作。一些语言将线程和同步操作视为高级抽象的一部分,并将它们作为原语公开,而其他一些语言只鼓励相对更高级别的原语(如期货/承诺)。

在特定于语言的线程级别下,存在底层托管环境(通常是操作系统)的多任务处理。操作系统级的抢占式多任务处理用于实现(抢占式)多线程。在Windows NT等环境中,基本调度单元(任务)也是“线程”。为了将它们与上面提到的线程的用户空间实现区分开来,它们被称为内核线程,其中“内核”指的是OS (然而,严格地说,这并不适用于Windows NT;“真正的”内核是NT执行程序)的内核。内核线程并不总是1:1映射到用户空间线程,尽管1:1映射通常会减少大部分映射开销。由于内核线程是创建/销毁/通信的重量级线程(涉及系统调用),所以用户空间中存在非1:1的绿色线程,以映射开销为代价来克服开销问题。映射的选择取决于高级抽象中预期的编程范型。例如,当大量的用户空间线程期望被并发执行时(如Erlang), 1:1映射永远是不可行的。

OS多任务处理的底层是处理器逻辑核心提供的isa级多任务处理。这通常是程序员使用的最低级的公共接口。在此级别之下,可能存在SMT。这是一种由硬件实现的更低级的多线程形式,但可以说,在某种程度上仍然是可编程的——尽管通常只有处理器制造商才能访问它。注意,硬件设计明显反映了并行性,但也有并行调度机制,使内部硬件资源得到有效利用。

在上面提到的每一层“线程”中,都涉及并发性和并行性。尽管编程接口变化很大,但它们都服从于一开始基本抽象所揭示的属性。

只是分享一个有助于突出区别的例子:

并行编程:假设你想实现< em > < / em >合并排序算法。每次将问题划分为两个子问题时,可以有两个线程来解决它们。然而,为了进行合并步骤,您必须等待这两个线程完成,因为合并需要两个子解决方案。这种“强制等待”使其成为并行程序。

假设你想要压缩n个文本文件并为它们每个生成一个压缩文件。您可以有2个(最多n个)线程,每个线程处理压缩文件的一个子集。当每个线程完成时,它就完成了,它不需要等待或做任何其他事情。因此,由于不同的任务以“任意顺序”交错的方式执行,所以程序是并发的,而不是并行的。

正如其他人提到的,每个并行程序都是并发的(事实上必须是),而不是相反。

我会试着用我自己的方式来解释它,它可能不是计算机术语,但它能给你一个大概的概念。

让我们以家务为例:洗碗,倒垃圾,修剪草坪等,我们有三个人(线程)A, B, C来做这些事情

< >强并发: 三个人独立地开始不同的任务,即

A --> cleaning dishes
B --> taking out trash
C --> mowing the lawn

在这里,任务的顺序是不确定的,响应取决于工作量

< >强并行: 在这里,如果我们想提高吞吐量,我们可以分配多个人来完成一项任务,例如,洗碗,我们分配两个人,A洗碗,B洗碗,可能提高吞吐量

洗碗:

A --> soaping the dishes
B --> washing the dishes

等等

希望这能给你一些启发!现在转到其他答案中解释的技术术语;)

并发提供了一种方法来构造解决方案,以解决可能(但不一定)可并行的问题, 并发性约为结构,并行性约为执行

enter image description here

并发:在单核机器上,< >强同时< / >强以cpu时间片共享的方式运行。
Parallel:在多核机器上,< >强同时< / >强同时运行在每个核中。

并发编程是一个通用概念,即一个程序可以以未定义的完成顺序执行多个任务,并且这些任务可以同时执行,也可以不同时执行。

并行编程只是一种并发编程,其中这些任务运行在同时执行的线程上。

我真的不理解这里许多过于冗长的回答,这些回答似乎暗示并行编程和并行编程是不同的编程方法,它们并不重叠。

如果你在写一个并行程序,根据定义,你是在写一个并发程序的特殊情况。这些年来,术语似乎被不必要地混淆和复杂化了。

关于并发编程最好和最详细的介绍之一是《concurrent programming on windows》这本书。作者:乔·达菲。这本书定义了并发,然后继续解释各种操作系统资源,库等可用来编写“并行”。程序,例如。net中的任务并行库。

第5页:

并行性是使用并发性将一个操作分解为 粒度更细的组成部分,以便独立的部分可以运行 机器上的独立处理器

同样,并行编程只是一种特殊类型的并发编程,其中多个线程/任务将同时运行。

< p > PS 我一直不喜欢在编程中,并发和并行这两个词有如此多的含义。例:在编程之外的广阔世界里,“篮球比赛将同时进行”。而且“篮球比赛将并行进行”。都是相同的。< / p >

想象一下开发者大会上可笑的混乱,他们在第一天就宣称会议将以“并行”方式运行。但在第二天,它们将“同时”运行。那会很搞笑的!