Answers:
除了Nish的答案外,让我推荐Simon Marlow关于Haskell中的并行和并发编程的书或他的简短教程。它们从Haskell的角度回答了您的第一个问题,因此它们可能更适合于理论上有偏见的读者(Haskell是一种纯函数式的惰性编程语言,比其他语言更接近于数学)。
从那里报价:
在许多领域,并行和并发是同义词。在编程中则不是这样,在编程中它们用来描述根本不同的概念。
并行程序是一种使用多个计算硬件(例如,多个处理器内核)以便更快速地执行计算的程序。计算的不同部分被委派给同时(并行)执行的不同处理器,因此与顺序执行计算相比,可以更早地交付结果。
相反,并发是一种程序结构技术,其中有多个控制线程。通常,控制线程“同时”执行;即,用户看到了他们的效果交错。它们是否实际上同时执行是实现细节。并发程序可以通过交错执行在单个处理器上执行,也可以在多个物理处理器上执行。
我建议阅读本教程的其余内容(第4页),但让我引用本节的其余部分,因为它将编程范例与程序的定量和定性特征(例如效率,模块化和确定性)联系在一起。
尽管并行编程仅涉及效率,但并行编程则涉及构建需要与多个独立外部代理(例如,用户,数据库服务器和某些外部客户端)交互的程序。并发允许将此类程序模块化。与用户交互的线程不同于与数据库交互的线程。在没有并发的情况下,此类程序必须使用事件循环和回调编写---实际上,即使并发可用,事件循环和回调也经常被使用,因为在许多语言中,并发要么太昂贵,要么太难采用。
“控制线程”的概念在纯功能程序中没有意义,因为没有要观察的效果,并且评估顺序也没有关系。因此,并发是有效代码的一种结构化技术。在Haskell中,这意味着IO monad中的代码。
相关的区别是确定性编程模型和非确定性编程模型。确定性编程模型是其中每个程序只能给出一个结果的模型,而非确定性编程模型则根据执行的某些方面允许可能具有不同结果的程序。并发编程模型不一定是确定性的,因为它们必须与在无法预测的时间导致事件的外部代理进行交互。非确定性有一些明显的缺点,但是:程序变得很难测试和推理。
对于并行编程,我们将尽可能使用确定性编程模型。由于目标只是为了更快地找到答案,因此我们宁愿不要使我们的程序在此过程中难以调试。确定性并行编程是两全其美的方法:可以在顺序程序上执行测试,调试和推理,但是添加处理器后程序的运行速度更快。实际上,大多数计算机处理器本身都以流水线和多个执行单元的形式实现确定性并行性。
尽管可以使用并发进行并行编程,但这通常是一个糟糕的选择,因为并发可以简化确定性。在Haskell中,并行编程模型是确定性的。但是,重要的是要注意,确定性编程模型不足以表示所有种类的并行算法。有些算法依赖于内部不确定性,尤其是涉及搜索解决方案空间的问题。在Haskell中,此类算法只能使用并发表示。
并行性和并行性在它们解决和引起的问题上有所不同,但它们不是独立的。
执行两个任务同时意味着两个任务的各个步骤以交错的方式被执行。如果不考虑并行性,则可以假定在任何时间点仅执行一条语句,但是(先验)不能保证执行下一步的任务。
这在某些方面很有用:
主要挑战包括:
执行两个任务并行意味着语句执行在同一时间。这主要用于:
关键挑战包括:
另请参阅此问题以区分并行计算和分布式计算。
对此有很多答案,但这可能会造成混淆。我喜欢这样想,也许有帮助吗?:
并发编程是不关心执行顺序的代码。Java是并发编程的一种糟糕的语言,但是有一些库和框架可以提供帮助。JavaScript是并发编程的优秀语言,当您要编写非并发的内容时(例如,如果要强制执行顺序),通常很难做到这一点。并发编程非常适合事件驱动的编程(事件的执行顺序由事件侦听器确定,例如单击按钮或在框中键入内容时在浏览器中运行的代码)。
一个示例包括创建一百个HTTP请求。在NodeJS中,最简单的解决方案是使用回调方法一次打开所有100个请求,然后当响应返回时,每次都执行一个方法。那是并发编程。在Ruby中,最简单(最常见)的解决方案是打开一个请求并处理响应,打开下一个请求并处理响应,等等。对于许多请求,NodeJS易于及时完成,尽管您必须注意避免重击服务器或最大化出站连接(容易犯错误)。您可以以并发方式编写Ruby,但这并不是大多数Ruby代码的编写方式,这样做会有些痛苦。
并行编程是可以在多个线程或进程中同时运行的代码。这使您可以通过在多个CPU(通常包括多台计算机,如Akka之类的设备)上运行代码来优化性能。因为NodeJS不是多线程的并且没有并行执行,所以您不必担心编写线程安全的代码(而且我见过的大多数JavaScript代码都不是线程安全的)。在Java中,即使该语言没有使并发编程成为正常模式,但并行编程是内置的,并且您经常不得不担心线程安全性。如果您使用Java编写网站,则通常会在一个容器中运行该容器,该容器在同一内存中的单独线程中运行每个请求,
以上某些内容取决于您所讨论的范围和界限。我在网站上工作。我看到的大多数Java代码都不是并发编程。当然,如果您放大得足够多,那么客户要求的输入顺序并不重要,但是如果您进一步放大,则执行代码的顺序将由代码决定。但是编写了代码,以便请求可以与许多必须是线程安全的共享对象并行执行。
同时,我看到的大多数JavaScript代码都是并发的:它的编写顺序在许多级别上都不重要。但这并不是为了支持共享内存中的并行执行而编写的。当然,您可以在多个进程中并行执行相同的代码,但是不会共享对象,因此从任何有意义的意义上讲,它都不是并行编程。
对于其他阅读,我真的很喜欢此问题的最高答案中的插图:https : //www.quora.com/What-are-the-differences-between-parallel-concurrent-and-asynchronous-programming