Go语言中常见100问题-#55 Mixing concurrency and parallelism

2022-08-15 15:20:48 浏览数 (1)

混淆并发和并行

即使拥有多年并发编程经验的开发者,也可能没有清楚地理解并发和并行的区别。在深入研究Go并发编程之前,通过一家咖啡店这个真实的生活的例子来说理清并发和并行概念的含义。

在这家咖啡店里,有一个服务员负责接单并用一台咖啡机制作咖啡。顾客下单之后,然后等待领取咖啡。如下图所示。

如果一个服务员很难为很多个客户提供服务并希望缩短客户排队等待时间,一个方法是增多一个服务员和一台咖啡机,这样等待的客户只要有两个服务员中任何一个有空,就可以为他提供服务。如下图所示。

在上面这个过程中,系统的每一个部分都是独立的。咖啡店可以以两倍的速度为顾客提供服务, 这是咖啡店的并行实现方法。

如果我们想扩大规模,只需要像上面这样,不断地增加服务员和咖啡机就可以。然而,这种方法并不是唯一的解决方法。另一种可行的方法是将服务员的工作分开,让一个服务员处理接收订单操作,另一个服务员负责制作咖啡。此外,可以让等待咖啡的顾客专门排一队,不阻塞还没下单的顾客。

在上面的方法中,并没有让整个流程并行进行,受影响的是整个结构,我们将一个角色分成了两个角色(接收订单和制作咖啡),并引入了另一个队列,咖啡机还是只有一个。与并行不同,并发性与结构有关。

现假设一个线程代表接收订单的服务员,另一个线程代表咖啡机,还有一个线程来准备咖啡。每个线程是独立的,但它们必须与其他线程协调才能工作。在这个例子中,接收订单的服务员线程必须说要哪种咖啡与咖啡线程通信,同时,准备咖啡的线程与咖啡机线程通信。

如果我们想增加吞吐量,例如,在一个小时内为更多顾客提供服务,怎么处理呢?由于准备咖啡比接受订单慢,可能的方法是再聘请一个服务员做咖啡。

在上面的流程结构任然是保持不变的。它任然是一个三步设计:接受订单、准备咖啡、煮咖啡。与上上个流程相比在并发方面是没有变化的,上上个流程也是一个三步设计。不同的是,上面这个流程中在准备咖啡的过程引入了并行,同时有多个服务员进行准备咖啡工作。

现在,让我们假设导致整个流程变慢的瓶颈在咖啡机。的确,只有一台咖啡机会导致准备咖啡的线程产生竞争,因为它们都在等待咖啡机线程,有什么解决方法吗?嗯,添加更多的咖啡机线程。如下图所示。

通过引入更多的咖啡机,提高了并行度。同样,上述流程任然是一个3步操作,结构没有发生变化。然而因为准备线程的竞争性下降,系统的吞吐量增加了。

通过上面这种设计,我们认识到一个重要事实:并发可以实现并行。实际上,并发提供了一种结构来解决可能并行化的部分。下面是Rob Pike对并发和并行精辟说明,并发是同一时间处理多件事情,并行是在同一时间做多件事情。

❝Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once. -- Rob Pike ❞

总结,并行和并发是不同的,并发关心结构,并行关心执行。并发是与结构相关的,我们可以引入单独的并发线程可以处理的不同步骤将顺序实现变为并发实现。并行是与执行相关的,可以通过在每个步骤上增加更多的并行线程来提高并行度。

0 人点赞