本节书摘来自异步社区《Haskell并行与并发编程》一书中的第1章,第1.1节学习术语:并行性和并发性,作者【英】Simon Marlow,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.1 术语:并行性和并发性
Haskell并行与并发编程
在许多领域并行和并发是同义词,但在编程中则不然,它们被用来描述在根本上完全不同的两个概念。
并行程序是指使用多个硬件参与计算(如多个处理器核心)使之更快的程序。目标是通过将计算的不同部分分配给不同的处理器,使之能够同时执行,从而更早得到问题的答案。
与之相对的,并发则是一种包含多个控制线程的程序构成技术。从概念上说,这些控制线程是“同时”被执行的,也就是说,用户所观察到的最终影响,是由这些线程交替作用产生的。到底是否真的是同时执行则属于实现上的细节。并发程序可以通过交替的方式在单个处理器上执行,或在多个物理处理器上执行。
并行编程仅关注效率,而并发编程则关注程序的构成,使之能够和多个独立的外部媒介交互(如用户、数据库或一些外部客户)。并发性使得这类程序能够模块化,和用户交互的线程可以明确地区分于和数据库通信的线程。在没有并发的情况下,这类程序必须通过事件循环和回调的方式编写,与线程所提供的相比,通常更加低效且模块化不足。
在纯函数式的程序中,“控制线程”这个概念是没有意义的,因为没有需要观测的效果,而且程序的结果也和求值的顺序无关。因此,并发性是用于构成产生效果的代码的技术;在Haskell中,即IO monad中的代码。
一个与之相关的内容是确定性和非确定性编程模型的区分。确定性编程模型中每个程序只会给出一个结果,而非确定性编程模型则容许——取决于执行时某些情况——程序可以有不同的结果。由于必须和外部媒介交互,而这些交互会导致事件在不可预测的时刻发生,所以并发编程模型必然是非确定性的。而非确定性有一些显著的缺点:程序将会变得非常难以测试和推断。
对于并行编程来说,应尽可能地使用确定性编程模型。既然目标仅仅是更快地获得答案,那么还是不要让程序在这个过程中变得更难调试。确定性并行编程是这两方面的最佳结合:测试、调试和推断可以以顺序的方式执行,但加入更多处理器后程序则能运行得更快。事实上,大多数计算机处理器自身通过流水线和多个执行单元的形式实现了确定性并行。
虽然可以使用并发的方式实现并行编程,但这通常不是一个明智的选择,因为并发的使用牺牲了确定性。在Haskell中,大多数的并行编程模型都是确定性的。然而,注意到确定性编程模型并不足以表达所有的并行算法是非常重要的,有些算法是依赖于内部不确定性的,特别是要对解空间进行搜索的问题。此外,有时希望并行化确实有副作用的程序,那就别无选择,只能使用非确定性并行编程或并发编程了。
最后,希望在同一个程序中混合使用并行和并发编程是完全合理的。大多数的交互式程序需要使用并发来维持一个快速响应的用户界面,与此同时在后台执行计算密集型的任务。