Go concurrency model :原文地址:
http://www.oschina.net/translate/go-concurrency-patterns-pipelines?print
特性:原子并发特性
优势:Golang可有效的使用I/O和多CPU特性。
1 什么是管道
在Golang对于管道没有明确的定义;它只是许多种并发程序中的一种。管道是通道连接的一系列阶段, 每个阶段是一组goroutine运行相同的功能。在每个阶段,goroutine运行步骤为:
-
从上游经过入境通道接受值
-
对数据执行一些功能操作,通常会产生新的值
-
从下游经过出境通道发送值
举个例子:
第一阶段:gen,以从列表读出整数的方式转换整数列表到一个通道。gen函数开始goroutine后,
在通道上发送整数并且在在所有的值被发送完后将通道关闭:
func gen(nums ...int) <-chan int { out := make(chan int) go func() { for _, n := range nums { out <- n } close(out) }() return out }
第二阶段:sq,从通道接受整数,然后将接受到的每个整数值的平方后返回到一个通道 。在入境通道关闭和发送所有下行值的阶段结束后,关闭出口通道:
func sq(in <-chan int) <-chan int { out := make(chan int) go func() { for n := range in { out <- n * n } close(out) 08 }() return out }main函数建立了通道并运行最后一个阶段:它接受来自第二阶段的值并打印出每个值,直到通道关闭:
func main() { // Set up the pipeline. c := gen(2, 3) out := sq(c) // Consume the output. fmt.Println(<-out) // 4 fmt.Println(<-out) // 9
扇出,扇入
扇出(fan-out):多个函数能从相同的通道中读数据,直到通道关闭;这提供了一种在一组“人员”中分发任务的方式,使得CPU和I/O的并行处理.
扇入(fan-in):一个函数能从多个输入中读取并处理数据,而这多个输入通道映射到一个单通道,该单通道随着所有输入的结束而关闭。
短暂停止
管道函数模型:
-
当所有的发送操作结束后, 阶段关闭他们的出境通道。
-
阶段持续接收来自入境通道的值,直到那些通道关闭。
这个模型允许每一个接收阶段通过range循环的写数据,确保一旦所有向下游发送的值发送成功,所有的goroutine退出。
但在一个真实的管道上,阶段并不总是接收所有的入境值。有时设计是这样的:接收者可能只需要一个子集值就能取得进展。更多时候是一个阶段早早的退出,因为一个入境值代表一个早期阶段的错误。 在这两种情况下接收者不应该等待剩余的值到达,我们想要早期阶段停止产生后续阶段不需要的值。
显式取消
当main没有接受完out所有的值就决定退出时,它必须告知上游状态(upstream stage)的goroutines,让它丢弃正在发送中的数据。通过在一个叫做done的channel上发送数据,即可实现。例子里有两个受阻的发送方,所以发送的值有两组:
下面列出了构建管道的指南:
-
状态会在所有发送操作做完后,关闭它们的流出 channel
-
状态会持续接收从流入 channel 输入的数值,直到 channel 关闭或者其发送者被释放。
管道要么保证足够能存下所有发送数据的缓冲区,要么接收来自接收者明确的要放弃 channel 的信号,来保证释放发送者。
有疑问加站长微信联系(非本文作者)