func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) { g.mu.Lock() // 初始化 map if g.m == nil { g.m = make(map[string]*call) } // 判断是否存在 key if c, ok := g.m[key]; ok { c.dups++ g.mu.Unlock() c.wg.Wait() // 存在的话就直接等待返回
if e, ok := c.err.(*panicError); ok { panic(e) } else if c.err == errGoexit { runtime.Goexit() } return c.val, c.err, true } c := new(call) c.wg.Add(1) g.m[key] = c g.mu.Unlock()
if e, ok := c.err.(*panicError); ok { if len(c.chans) > 0 { go panic(e) select {} // Keep this goroutine around so that it will appear in the crash dump. } else { panic(e) } } else if c.err == errGoexit { // Already in the process of goexit, no need to call again } else { // Normal return for _, ch := range c.chans { // chans 不为空时,将返回数据回写。 ch <- Result{c.val, c.err, c.dups > 0} } } }() func() { defer func() { if !normalReturn { // 请求发生错误的兜底 recover if r := recover(); r != nil { c.err = newPanicError(r) } } }()