/core/syncx/singleflight.go
func (g *flightGroup) Do(key string, fn func() (any, error)) (any, error) {
c, done := g.createCall(key)
if done {
// 此时,第一个协程执行完了,其他协程直接拿结果就行了。
return c.val, c.err
}
// 第一个到达的协程,执行任务函数fn。
g.makeCall(c, key, fn)
return c.val, c.err
}
第一个协程到达,此时没有任务,新建call记录,其他协程就知道了已经有人再做了。
func (g *flightGroup) createCall(key string) (c *call, done bool) {
g.lock.Lock()
// 查看这个key是否已有其他协程在执行
if c, ok := g.calls[key]; ok {
g.lock.Unlock()
// 等其他协程执行完
c.wg.Wait()
// 拿到其他协程执行完所得到的结果。(自己就不必亲自做一遍)
return c, true
}
// 我是第一个协程A,算了,我执行亲自做一遍吧,然后把结果共享给其他同样请求的协程。
c = new(call)
c.wg.Add(1)
// 其他协程调用,就知道我正在执行,您们就等着摘果实吧。
g.calls[key] = c
g.lock.Unlock()
// 第一个协程,返回false,意思是现在就去执行一下任务。
return c, false
}
第一个协程,执行任务函数fn(),返回结果 赋值于 c.val
func (g *flightGroup) makeCall(c *call, key string, fn func() (any, error)) {
defer func() {
g.lock.Lock()
// 第一个协程执行完任务,就删除任务key了,其他同一时刻的相同请求协程,反正都查询key过了,且都在等待中。
delete(g.calls, key)
g.lock.Unlock()
c.wg.Done()
}()
// 第一个协程,执行任务函数fn(),返回结果 赋值于 c.val
c.val, c.err = fn()
}