Golang Context 的实现
有这样一个场景: 父 goroutine 创建了多个子 goroutine 来处理某个请求,当这些子 goroutine 中任何一个出错的时候,我们希望所有的 goroutine 都停止。 该如何实现呢? 熟悉 Go 语言的可能首先想到用 context,而 context 主要是依靠 channel 来实现以上功能。 看了一下具体的实现,主要思想是: 每种类型的 ctx 都实现了 context.Context 接口的 Done() 函数 Done() <-chan struct{} 函数返回一个只读的 channel 而且没有地方向这个channel里写数据。所以直接调用这个只读channel会被阻塞。 一般通过搭配 select 来使用。一旦 channel 关闭,就会立即读出零值。 谁来关闭这个 channel 呢? 用户主动调用返回的 CancelFunc,或者 timeout 超时 另外,在使用上配合 select 语句阻塞处理 Done() 才能起到预期的效果。 下面举两个如何使用 context 的例子,第一个例子如下 func main() { ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() go handle(ctx) // 等待3秒再结束(只是为了让 main 不提前 exit,与本文无关) select { case <- time.After(3*time.Second): fmt.Println("main", ctx.Err()) } } func handle(ctx context.Context) { select { case <-ctx.Done(): fmt.Println("goroutine ", ctx.Err()) // 处理请求,在这里我们用 time.After() 表示处理了多久, 也可以写成这样 // case ret, ok := <-req: case <-time.After(2*time.Second): fmt.Println("process request done") } } 在这个例子中,ctx 会在1秒后超时,而 goroutine 处理某个 request 需要 2 秒(在代码中用 time.After 代替真正的处理时间)。 ...