Singleflight
singleflight 来源于准官方库 golang.org/x/sync/singleflight,能够抑制对下游的多次重复请求。主要提供了以下三个方法: // Do(): 相同的 key,fn 同时只会执行一次,返回执行的结果给 fn 执行期间,所有使用该 key 的调用 // v: fn 返回的数据 // err: fn 返回的err // shared: 表示返回数据是调用 fn 得到的还是其他相同 key 调用返回的 func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) // DoChan(): 类似 Do() 方法,以 chan 返回结果 func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result // Forget(): 失效 key,后续对此 key 的调用将执行 fn,而不是等待前面的调用完成 func (g *Group) Forget(key string) 使用方法 package main import ( "context" "fmt" "golang.org/x/sync/singleflight" "sync/atomic" "time" ) type Result string func find(ctx context.Context, query string) (Result, error) { return Result(fmt.Sprintf("result for %q", query)), nil } func main() { var g singleflight.Group const n = 5 waited := int32(n) done := make(chan struct{}) key := "https://weibo.com/1227368500/H3GIgngon" for i := 0; i < n; i++ { go func(j int) { v, _, shared := g.Do(key, func() (interface{}, error) { ret, err := find(context.Background(), key) return ret, err }) if atomic.AddInt32(&waited, -1) == 0 { close(done) } fmt.Printf("index: %d, val: %v, shared: %v\n", j, v, shared) }(i) } select { case <-done: case <-time.After(time.Second): fmt.Println("Do hangs") } } 输出结果如下: ...
