网上有好多文章介绍了singleflight,但是这些文章似乎漏了一个点,让我想不明白:请求的值会放在map里,那这个值什么时候失效呢?如果不失效的话,那每次不都是拿的同一个值,每次都不调用数据库了,这和平时使用是对不上的。
singleflight的原理是:比如100个请求同时打到数据库,用了singleflight就会只有前一个请求打到数据库,后面99个会阻塞,等待第一个请求返回结果,后面99个用第一个请求拿到的结果。第一个请求返回后,会把这次的结果删掉。 singleflight是用来解决缓存击穿的问题。缓存击穿其中一种解决思路就是多个请求同时抢一个锁,抢到锁的去请求数据库,其他的等待。singleflight的实现和这种思路我认为是一致的。 singleflight 的实现原理就是 用了map和waitgroup
具体原理其他文章都有 主要关注的是下面的删除key。他这行代码表示结果返回后把存的这个key删除。删除前判断一下是不是原始的value, 因为有可能在此期间异步携程调用了Forget函数,误删别人设置的value
func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
normalReturn := false
recovered := false
// use double-defer to distinguish panic from runtime.Goexit,
// more details see https://golang.org/cl/134395
defer func() {
// the given function invoked runtime.Goexit
if !normalReturn && !recovered {
c.err = errGoexit
}
g.mu.Lock()
defer g.mu.Unlock()
c.wg.Done()
if g.m[key] == c {
fmt.Println("del m") // 注释
delete(g.m, key)
}
...