// propagateCancel arranges for child to be canceled when parent is.func propagateCancel(parent Context, child canceler) { if parent.Done() == nil { return // parent is never canceled } if p, ok := parentCancelCtx(parent); ok { p.mu.Lock() if p.err != nil { // parent has already been canceled child.cancel(false, p.err) } else { if p.children == nil { p.children = make(map[canceler]struct{}) } p.children[child] = struct{}{} } p.mu.Unlock() } else { // 开始不太理解这里: // 1.在cancel函数里会主动的将所有child cancel掉,为何还要这个协程来进行cancel。 // 2.为何还要监听 child.Done(). // 解答: // 1. 注意下这里的if else 结构,能走到这里的条件是,向上查找父context的过程中,没有发现cancleCtx的context。而只有cancelCtx有cancel函数。没有cancel函数的话,只能这样用协程的方式监听Done()了。 // 2.监听child.Done()是因为child执行结束或被cancel的时候,这个协程就可以退出了,没必要等parent结束。 go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() }}