看看 Singleflight

在看前辈的代码时,发现了一个缓存放穿透的处理,好奇就点进去看了,发现代码意外的少,于是就研究起来,为数不多我能看明白的源码T-T

源码地址:https://cs.opensource.google/go/x/sync/+/036812b2:singleflight/singleflight.go

看看 Singleflight
type call struct {
   wg sync.WaitGroup
   val interface{}
   err error
   forgotten bool
   // 统计被拦截调用fn的请求数,可以不关心
   dups  int
   // DoChan 中用的,先不关心
   chans []chan 0
}

// 调用fn()
func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
   normalReturn := false
   recovered := false

   defer func() {

      if !normalReturn && !recovered {
         c.err = errGoexit
      }

      c.wg.Done()
      g.mu.Lock()
      defer g.mu.Unlock()
      if !c.forgotten {
         delete(g.m, key)
      }

      if e, ok := c.err.(*panicError); ok {
         if len(c.chans) > 0 {
            go panic(e)
            select {}
         } else {
            panic(e)
         }
      } else if c.err == errGoexit {
      } else {
         for _, ch := range c.chans {
            ch  0}
         }
      }
   }()

   func() {
      defer func() {
         // 个人理解:当fn() panic的时候在这里recover,预防死锁
         if !normalReturn {
            if r := recover(); r != nil {
               c.err = newPanicError(r)
            }
         }
      }()

      c.val, c.err = fn()
      normalReturn = true
   }()

   if !normalReturn {
      recovered = true
   }
}

// 个人理解:释放这个key,使更多的请求调用请求到下游服务。当调用下游服务需要消耗大量时间时,
// 并发环境下,在调用下游服务时,只有一个请求会调用到下游服务,其他请求会被阻塞,当这个请求失败时,会严重影响效率。
// 如果启动Goroutine 定时Forget,则会释放更多的请求到下游服务,提高并发和容错。
func (g *Group) Forget(key string) {
   g.mu.Lock()
   if c, ok := g.m[key]; ok {
      c.forgotten = true
   }
   delete(g.m, key)
   g.mu.Unlock()
}

Original: https://www.cnblogs.com/weirwei/p/15404173.html
Author: weirwei
Title: 看看 Singleflight

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/591864/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球