并发编程和并行编程有什么区别?

时间:2009-12-13 22:17:47

标签: language-agnostic parallel-processing concurrency

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

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

18 个答案:

答案 0 :(得分:376)

并发编程关于看似重叠的操作,主要关注由于非确定性控制流而引起的复杂性。与并发程序相关的定量成本通常是吞吐量和延迟。并发程序通常是IO绑定但不总是,例如,并发垃圾收集器完全在CPU上。并发程序的教学示例是Web爬行程序。该程序启动对网页的请求,并在下载结果可用时同时接受响应,累积已经访问过的一组页面。控制流是不确定的,因为每次运行程序时,响应不一定以相同的顺序接收。这种特性使得调试并发程序变得非常困难。一些应用程序基本上是并发的,例如Web服务器必须同时处理客户端连接。 Erlang可能是即将推出的高度并发编程语言。

并行编程涉及为提高吞吐量的特定目标而重叠的操作。通过使控制流确定性来避免并发编程的困难。通常,程序会生成并行运行的子任务集,而父任务仅在每个子任务完成后才会继续。这使得并行程序更容易调试。并行编程的难点在于粒度和通信等问题的性能优化。后者在多核的背景下仍然是一个问题,因为将数据从一个缓存传输到另一个缓存有相当大的成本。密集矩阵 - 矩阵乘法是并行编程的一个教学实例,它可以通过使用Straasen的分而治之算法并行地攻击子问题来有效地求解。 Cilk可能是共享内存计算机(包括多核)上最有前途的高性能并行编程语言。

答案 1 :(得分:287)

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

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

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

线程计算机上的主题:

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

破折号代表执行的代码。正如您所看到的,它们分开并单独执行,但线程化的机器可以同时执行多个单独的部分。

答案 2 :(得分:130)

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

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

平行=两个队列和两台咖啡机。

答案 3 :(得分:31)

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

并发计算中,两个计算都相互独立地前进。第二次计算不必等到第一次计算结束才能推进。然而,它没有说明如何实现这一目标的机制。在单核设置中,需要在线程之间挂起和交替(也称为抢先多线程)。

并行计算中,两个计算同时进行 - 这实际上是同时进行的。单CPU不可能实现这一点,而是需要多核设置。

  

suspending and taking turnsparallel computing

根据:"Parallel vs Concurrent in Node.js"

答案 4 :(得分:21)

在处理器的视图中,可以用这张图片来描述

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

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

答案 5 :(得分:19)

我认为并发编程是指多线程编程,它让你的程序运行多个线程,从硬件细节中删除。

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

答案 6 :(得分:13)

我在一些博客中发现了这个内容。认为它是有用的和相关的。

并发和并行不是一回事。如果两个任务在时间上执行的顺序没有预先确定,则两个任务T1和T2是并发的,

T1可以在T2之前执行并完成, T2可以在T1之前执行并完成, T1和T2可以在相同的时间(并行性)同时执行, T1和T2可以交替执行, ... 如果操作系统调度两个并发线程在一个单核非SMT非CMP处理器上运行,则可能会获得并发但不能并行。在多核,多处理器或分布式系统上可以实现并行化。

并发通常被称为程序的属性,并且是一种比并行性更通用的概念。

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

答案 7 :(得分:7)

答案 8 :(得分:5)

  

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

并且

  

并发是独立执行的组合   计算。并发是一种结构化软件的方法,尤其是   作为编写与现实世界良好交互的干净代码的一种方式。   这不是平行主义。

     

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

为了理解这种差异,我强烈建议看看这个Rob Pike(Golang创作者之一)的视频。 Concurrency Is Not Parallelism

答案 9 :(得分:5)

任务的经典计划可以是串行并行并发

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

  • 并行:任务必须同时执行,否则无效。

    • 任何任务失败 - 无论是在功能上还是在时间上 - 都将导致系统完全失效。
    • 所有任务必须具有共同的可靠时间感。

    尽量避免这种情况,否则我们会在下午茶时间流泪。

  • 并发:我们不在乎。但是,我们并非粗心大意:我们已经对它进行了分析,并不重要;因此,我们可以随时使用任何可用设施执行任何任务。快乐的日子。

通常,可用的调度会在已知事件中发生变化,我们将其称为状态更改。

人们通常认为这是关于软件的,但事实上它是一种系统设计概念,它早于计算机;软件系统的使用速度有点慢,很少有软件语言试图解决这个问题。如果您有兴趣,可以尝试查找晶片机语言 occam

简洁地说,系统设计解决了以下问题:

  • 动词 - 你在做什么(操作或算法)
  • 名词 - 你在做什么(数据或接口)
  • 何时 - 启动,安排,状态变更
  • how - serial,parallel,concurrent
  • 在哪里 - 一旦你知道事情何时发生,你可以说出它们可能发生的地方,而不是之前。
  • 为什么 - 这是这样做的方法吗?还有其他方式,更重要的是,更好的方式吗?如果你不这样做会怎么样?
祝你好运。

答案 10 :(得分:5)

并行编程在代码同时执行且每次执行独立于另一个时发生。因此,通常没有关于共享变量的关注,因为这不可能发生。

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

答案 11 :(得分:5)

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

  •   
  • Parallel programming具体是指在不同处理器上同时执行并发任务。因此,所有   并行编程是并发的,但并非所有并发编程   是平行的。

  •   

来源:PThreads Programming - A POSIX Standard for Better Multiprocessing, Buttlar, Farrell, Nichols

答案 12 :(得分:3)

我明白区别是:

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

所以你可以让两件事情在彼此独立的情况下同时发生,即使他们在第(2)点聚集在一起,或者两件事情在整个执行的操作中都使用相同的储备(1)。

答案 13 :(得分:1)

虽然没有完整 关于术语 parallel 并发之间的区别的协议, 许多作者做出以下区分:

  • 在并发计算中,程序是指任何时刻都可以进行多项任务的程序。
  • 在并行计算中,程序是多个任务密切配合的程序 解决问题。

所以并行程序是并发的,但是多任务操作系统之类的程序也是并发的,即使它是在一台机器上运行的 只有一个核心,因为任何时刻都可以进行多项任务。

来源:并行编程简介, Peter Pacheco

答案 14 :(得分:1)

我将尝试以我自己的风格来解释它,它可能不是计算机术语,但它为您提供了总体思路。

让我们举个例子,比如做家务:清洁餐具,清除垃圾,修剪草坪等,我们也有3个人(线程)A,B,C来做

并发: 这三个人独立地执行不同的任务,即

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

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

并行: 在这里,如果我们想提高吞吐量,我们可以将多个人分配给一个任务,例如,清洗碗碟我们分配两个人,A用肥皂洗碗,B洗碗,这可能会提高吞吐量。

洗碗:

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

等等

希望这能给您一个想法!现在转到其他答案中解释的技术术语;)

答案 15 :(得分:0)

并发性和并行性 Source

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

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

当进程中的线程数少于或等于处理器时,线程支持系统以及操作环境将确保每个线程在不同的处理器上运行。

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

答案 16 :(得分:0)

在不同的特定情况下,不同的人谈论不同种类的并发和并行性,因此需要一些抽象来掩盖其共同性质。

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

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

对于一般区别,请参见relevant answer,以了解并发与并行性的基本观点。(还有一些包含其他来源的链接。)

并发编程和并行编程是在某些具有可编程性的系统上实现此类一般属性的技术。这些系统通常是编程语言及其实现。

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

尽管基元在最高级的抽象中将复杂的对象抽象开了,但实现仍具有语言功能未暴露的额外复杂性。因此,需要一些中级抽象。一个典型的例子是 threading 。线程允许一个或多个执行线程(或简称为线程;有时也称为进程,这不一定是语言实现(运行时)支持的操作系统中计划的任务。线程通常是由运行时抢先调度的,因此线程不需要了解其他线程。因此,只要线程不共享任何内容(关键资源),线程就很自然地实现并行化:只需分解不同线程中的计算,一旦基础实现允许执行过程中计算资源的重叠,作品。线程还受共享资源的并发访问的约束:仅以任何顺序访问资源都将满足算法所需的最小约束,并且实现将最终确定何时访问。在这种情况下,可能需要执行一些同步操作。一些语言将线程和同步操作视为高级抽象的一部分,并将它们公开为原语,而其他一些语言则仅鼓励使用相对高级的原语(例如futures/promises)。

在特定于语言的线程级别下,基础托管环境(通常是OS)进行多任务处理。操作系统级别的抢占式多任务用于实现(抢占式)多线程。在某些环境(如Windows NT)中,基本计划单元(任务)也是“线程”。为了与上述线程的用户空间实现区分它们,它们称为内核线程,其中“内核”是指操作系统的内核(但是,严格来讲,对于Windows NT而言并不完全是这样;“真实”内核是NT主管)。内核线程并不总是1:1映射到用户空间线程,尽管1:1映射通常会减少大多数映射开销。由于内核线程是创建/销毁/通信的重量级(涉及系统调用),因此在用户空间中不存在1:1 green threads来克服开销问题,但以映射开销为代价。映射的选择取决于高级抽象中期望的编程范例。例如,当预期同时执行大量用户空间线程时(例如Erlang),1:1映射永远是不可行的。

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

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

答案 17 :(得分:0)

仅分享一个有助于突出区分的示例:

并行编程:假设您要实现 合并排序算法 。每次将问题分为两个子问题时,都可以有两个线程来解决。但是,为了执行合并步骤,您必须等待这两个线程完成,因为合并需要两个子解决方案。这种“强制等待”使它成为并行程序。

并发程序:假设您要 压缩n个文本文件 并为每个文本文件生成一个压缩文件。您可以有2个(最多n个)线程,每个线程都处理压缩文件的子集。每个线程完成后,就完成了,不必等待或执行任何其他操作。因此,由于以“任意顺序”以交错的方式执行不同的任务,因此程序是并发的,而不是并行的。

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