在并发编程中,许多编程语言采用共享内存/状态模型。然而,Go 通过实现 通信顺序进程 (CSP) 区别于众多语言。在 CSP 中,一个程序由并行的进程组成,这些进程不共享状态,而是使用通道进行通信和同步它们的操作。因此,对于有意采用 Go 的开发人员来说,理解通道的工作原理变得至关重要。在本文中,我将使用 Gopher 运行他们的虚构咖啡馆的可爱比喻来阐述通道,因为我坚信人类更容易通过视觉学习。
情景
Partier、Candier 和 Stringer 经营一家咖啡馆。由于制作咖啡需要比接受订单更多的时间,Partier 将协助接受客户的订单,然后将这些订单传递到厨房,Candier 和 Stringer 在那里制作咖啡。
Gopher's Cafe
无缓冲通道
最初,咖啡馆以最简单的方式运营:每当收到新订单时,Partier 将订单放入通道中,并等待 Candier 或 Stringer 中的任何一个在接受新订单之前取走它。这种 Partier 和厨房之间的通信是通过无缓冲通道实现的,使用 ch := make(chan Order) 创建。当通道中没有待处理的订单时,即使 Stringer 和 Candier 都准备好接受新订单,它们也会保持空闲状态,等待新订单到来。
无缓冲通道
当收到新订单时,Partier 将其放入通道中,使订单可以被 Candier 或 Stringer 之一接受。但是,在继续接受新订单之前,Partier 必须等待其中一个从通道中获取订单。
由于 Stringer 和 Candier 都可以接受新订单,因此订单将立即被其中一个接受。但是,不能保证或预测哪个具体的接收者会获取订单。在 Stringer 和 Candier 之间的选择是非确定性的,它依赖于诸如调度和 Go 运行时的内部机制等因素。假设 Candier 获取了第一个订单。
Candier 完成处理第一个订单后,她回到等待状态。如果没有新订单到达,那么 Candier 和 Stringer 这两名工作人员都会保持空闲状态,直到 Partier 将另一个订单放入通道中供他们处理。
当新订单到达并且 Stringer 和 Candier 都可以处理它时,即使 Candier 刚刚处理了前一个订单,接收新订单的具体工作人员仍然是不确定的。在这种情况下,假设 Candier 再次被分配为第二个订单的接收者。
在新订单 order3 到达时,Candier 正在处理 order2,她没有等待在行 order :=