golang的context代码有点困惑

sleagon · · 209 次点击 · 开始浏览    置顶
最近在context的源码,看到这么一段,其中不太理解这个progageteCancel里的两个if,第一个parent.Done() == nil 按说已经过滤出background和todo了,后面再用parentCancelCtx为啥还要来一次,按说除了background和todo外的其他context也不会走到这里撒。 这里难道是为了让开发者可以自己去实现Context这个interface,然后通过WithCancel这样的方式来衔接后续的动作,这么做有什么具体意义吗? ```golang // 这一块实现的是保证cancel链路完整,结束动作能够顺利沿着链路传递下去 func propagateCancel(parent Context, child canceler) { // 这里找到父节点的Done,如果是nil显然只能是background或者todo了撒 if parent.Done() == nil { return // parent is never canceled } // 这里会调用parentCancelCtx,我个人理解是从链路上找到一个cancelCtx // 但是看源码基本也识别了所有类型了,剩下的无非也就是background和todo // 了,是不是说这里不可能进到else呢? if p, ok := parentCancelCtx(parent); ok { p.mu.Lock() // 如果父节点已经被cancel掉了,就把字节点也cancel掉 if p.err != nil { // parent has already been canceled child.cancel(false, p.err) } else { if p.children == nil { // 因为golang没有set,所以这里拿map做为set用 // 这里也看到了,实际上p.children下存的并不是完整的 // 子节点,只是留下了部分在关闭时候需要用到的方法罢了 // 可以理解canceler是cancelCtx的一个子集 p.children = make(map[canceler]struct{}) } // 记录子节点 p.children[child] = struct{}{} } p.mu.Unlock() } else { // 开一个goroutine去监控,如果父节点结束了,就关掉子节点 // 如果子节点结束了就算了 go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() } } // 认识所有的context,从parent对象上找一个cancelCtx,用来衔接cancel链路 func parentCancelCtx(parent Context) (*cancelCtx, bool) { for { switch c := parent.(type) { case *cancelCtx: return c, true case *timerCtx: return &c.cancelCtx, true case *valueCtx: parent = c.Context default: return nil, false } } } ```
209 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传