We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SingleFlight是Go语言sync扩展库提供的另一种并发原语,那么SingleFlight是用于解决什么问题的呢?官方文档里的解释是:
SingleFlight
sync
Package singleflight provides a duplicate function call suppression mechanism. 翻译过来就是:singleflight包提供了一种抑制重复函数调用的机制。
Package singleflight provides a duplicate function call suppression mechanism.
翻译过来就是:singleflight包提供了一种抑制重复函数调用的机制。
具体到Go程序运行的层面来说,SingleFlight的作用是在处理多个goroutine同时调用同一个函数的时候,只让一个goroutine去实际调用这个函数,等到这个goroutine返回结果的时候,再把结果返回给其他几个同时调用了相同函数的goroutine,这样可以减少并发调用的数量。在实际应用中也是,它能够在一个服务中减少对下游的并发重复请求。还有一个比较常见的使用场景是用来防止缓存击穿。
Go
goroutine
Go扩展库里用singleflight.Group结构体类型提供了SingleFlight并发原语的功能。
singleflight.Group
singleflight.Group类型提供了三个方法:
func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result func (g *Group) Forget(key string)
fn
使用缓存时,一个常见的用法是查询一个数据先去查询缓存,如果没有就去数据库里查到数据并缓存到Redis里。缓存击穿问题是指,高并发的系统中,大量的请求同时查询一个缓存Key 时,如果这个 Key 正好过期失效,就会导致大量的请求都打到数据库上,这就是缓存击穿。用 SingleFlight 来解决缓存击穿问题再合适不过,这个时候只要这些对同一个 Key 的并发请求的其中一个到数据库中查询就可以了,这些并发的请求可以共享同一个结果。用 SingleFlight能够限制对同一个缓存 Key 的多次重复请求,减少对下游的瞬时流量。 下面是一个模拟用SingleFlight并发原语合并查询Redis缓存的程序,你可以自己动手测试一下,开10个goroutine去查询一个固定的Key,观察一下返回结果就会发现最终只执行了一次Redis查询。
Redis
// 模拟一个Redis客户端 type client struct { // ... 其他的配置省略 requestGroup singleflight.Group } // 普通查询 func (c *client) Get(key string) (interface{}, error) { fmt.Println("Querying Database") time.Sleep(time.Second) v := "Content of key" + key return v, nil } // SingleFlight查询 func (c *client) SingleFlightGet(key string) (interface{}, error) { v, err, _ := c.requestGroup.Do(key, func() (interface{}, error) { return c.Get(key) }) if err != nil { return nil, err } return v, err }
完整可运行的示例代码,访问:https://github.com/kevinyan815/gocookbook/tree/master/codes/singleflight 。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
SingleFlight
是Go语言sync
扩展库提供的另一种并发原语,那么SingleFlight
是用于解决什么问题的呢?官方文档里的解释是:具体到
Go
程序运行的层面来说,SingleFlight
的作用是在处理多个goroutine
同时调用同一个函数的时候,只让一个goroutine
去实际调用这个函数,等到这个goroutine
返回结果的时候,再把结果返回给其他几个同时调用了相同函数的goroutine
,这样可以减少并发调用的数量。在实际应用中也是,它能够在一个服务中减少对下游的并发重复请求。还有一个比较常见的使用场景是用来防止缓存击穿。Go
扩展库里用singleflight.Group
结构体类型提供了SingleFlight
并发原语的功能。singleflight.Group
类型提供了三个方法:fn
函数。同一个 key,在同一时间只有第一次调用Do方法时才会去执行fn
函数,其他并发的请求会等待调用的执行结果。fn
函数执行完,产生了结果以后,就能从这个 chan 中接收这个结果。fn
函数,而不是等待前一个未完成的fn
函数的结果。使用缓存时,一个常见的用法是查询一个数据先去查询缓存,如果没有就去数据库里查到数据并缓存到
Redis
里。缓存击穿问题是指,高并发的系统中,大量的请求同时查询一个缓存Key 时,如果这个 Key 正好过期失效,就会导致大量的请求都打到数据库上,这就是缓存击穿。用SingleFlight
来解决缓存击穿问题再合适不过,这个时候只要这些对同一个 Key 的并发请求的其中一个到数据库中查询就可以了,这些并发的请求可以共享同一个结果。用SingleFlight
能够限制对同一个缓存 Key 的多次重复请求,减少对下游的瞬时流量。下面是一个模拟用
SingleFlight
并发原语合并查询Redis
缓存的程序,你可以自己动手测试一下,开10个goroutine
去查询一个固定的Key,观察一下返回结果就会发现最终只执行了一次Redis
查询。完整可运行的示例代码,访问:https://github.com/kevinyan815/gocookbook/tree/master/codes/singleflight 。
The text was updated successfully, but these errors were encountered: