在看前辈的代码时,发现了一个缓存放穿透的处理,好奇就点进去看了,发现代码意外的少,于是就研究起来,为数不多我能看明白的源码T-T
源码地址:https://cs.opensource.google/go/x/sync/+/036812b2:singleflight/singleflight.go
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/
转载文章受原作者版权保护。转载请注明原作者出处!