go singleflight

436 阅读1分钟

网上有好多文章介绍了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)
                }
                ...

源码