新闻详情

新闻详情

首页 / 资讯中心 / 详情

Golang singleflight 快速上手

发布时间:2026/8/1 3:51:39
Golang singleflight 快速上手
文章目录1.简介2.适用场景3.核心方法4.快速上手示例4.1 安装4.2 基本用法5.注意事项6.生产级使用示例带超时控制7.总结1.简介singleflight 是 Go 标准库扩展包golang.org/x/sync/singleflight提供的一个**请求合并请求抑制**工具。singleflight 的核心作用是在多个并发请求同时调用同一个函数时只让第一个请求真正执行其他请求会等待并共享第一个请求的结果。2.适用场景缓存击穿当缓存过期瞬间大量并发请求同时打到数据库singleflight 可以保证只有一个请求去查 DB其他请求等待结果。防止重复计算多个请求同时触发同一个昂贵的计算如生成报告、查询大数据。防止重复 RPC 调用在微服务中多个上游同时请求同一个下游接口时合并请求。3.核心方法方法说明Do(key string, fn func() (interface{}, error)) (interface{}, error, bool)同步执行相同 key 的并发请求只执行一次 fn其他等待结果。返回值shared表示结果是否被共享。DoChan(key string, fn func() (interface{}, error)) -chan Result异步版本返回一个 channel结果通过 channel 返回。Forget(key string)主动清除某个 key 的正在执行状态。下次对该 key 的Do会重新执行而不是等待之前的执行结果。4.快速上手示例4.1 安装go get golang.org/x/sync/singleflight4.2 基本用法packagemainimport(fmtsynctimegolang.org/x/sync/singleflight)// 模拟一个耗时操作比如查询数据库funcfetchDataFromDB(keystring)(string,error){fmt.Printf( 真正执行查询: key%s\n,key)time.Sleep(2*time.Second)// 模拟耗时returnresult_for_key,nil}funcmain(){varg singleflight.Groupvarwg sync.WaitGroup key:user_123concurrency:5fori:0;iconcurrency;i{wg.Add(1)gofunc(idint){deferwg.Done()// Do 方法第一个参数是 key用于去重第二个参数是实际执行的函数result,err,shared:g.Do(key,func()(interface{},error){returnfetchDataFromDB(key)})iferr!nil{fmt.Printf(goroutine %d got error: %v\n,id,err)return}fmt.Printf(goroutine %d got result: %v (shared%v)\n,id,result,shared)}(i)}wg.Wait()}输出大致顺序 真正执行查询: keyuser_123 goroutine 3 got result: result_for_user_123 (sharedtrue) goroutine 0 got result: result_for_user_123 (sharedtrue) ...关键点fetchDataFromDB只被执行了一次只有第一个 goroutine 触发了它。其他 4 个 goroutine等待并共享了第一个的结果。shared为true表示这个结果是和其他调用者共享的。5.注意事项panic 传播如果fn中发生 panicDo会重新 panic不会吞掉异常。建议在fn内部做好 recover。结果共享同一个 key 的多个调用者会共享同一个结果包括错误。如果第一个执行返回错误所有等待者都会收到该错误。key 的作用域singleflight.Group的 key 只在同一个 Group 实例中有效。不同 Group 实例之间的 key 互不影响。内存泄漏风险如果Do的fn执行时间很长甚至永不返回Group会一直持有该 key 的状态导致内存累积。对于长期运行的 key可以考虑在适当时候调用Forget。6.生产级使用示例带超时控制funcGetUserWithCache(ctx context.Context,userIDstring)(*User,error){// 先查缓存...ifcached,ok:cache.Get(userID);ok{returncached,nil}// 使用 singleflight 防止缓存击穿result,err,_:singleflightGroup.Do(userID,func()(interface{},error){// 加个超时控制避免长时间阻塞ctx,cancel:context.WithTimeout(ctx,500*time.Millisecond)defercancel()user,err:fetchUserFromDB(ctx,userID)iferr!nil{returnnil,err}cache.Set(userID,user)returnuser,nil})iferr!nil{returnnil,err}returnresult.(*User),nil}7.总结singleflight 请求合并器确保同一时间对同一个 key 的多个并发请求只执行一次其他请求共享结果。特别适合防止缓存击穿和重复计算。
网站建设 高端定制 企业官网