go并发编程 —— singleflight设计模式
什么是singleflight
singleflight是一种并发编程设计模式,将同一时刻的多个并发请求合并成一个请求,以减少对下游服务的压力
为什么叫singleflight
fly可以理解为请求数,singleflight就是单个请求
使用场景
该模式主要用于防止缓存击穿
例如当本地缓存失效时,为了防止大量请求都打到远程缓存redis,可以用singleflight保证该时刻只会有一个请求发到远程缓存:

或者当远程缓存失效时,为了防止大量请求都打到db,可以用singleflight保证该时刻只有一个请求发往db查询数据:

本文将比较go-zero和官方库对singleflight的实现
Go-zero
代码地址:https://github.com/zeromicro/go-zero/blob/master/core/syncx/singleflight.go
go-zero中对singleflight的定义如下:
type (SingleFlight interface {Do(key string, fn func() (any, error)) (any, error)DoEx(key string, fn func() (any, error)) (any, bool, error)}call struct {wg sync.WaitGroupval anyerr error}flightGroup struct {calls map[string]*calllock sync.Mutex}
)
-
SingleFlight:接口定义,调Do或DoEx用单并发的方式对资源发起请求
- 参数key:资源的标识
- 参数fn:真正请求获取资源的方法
- DoEx的第二个返回值bool: 表示从共享获取的,还是发起真实请求获取的
-
call:表示同一时刻对一个资源的一组请求
- wg:这一组的goroutine都阻塞在该wg上
- val,err:请求的返回值,err
-
flightGroup:总控结构
- calls:维护了正在执行中的call
我们看Do做了啥
func (g *flightGroup) Do(key string, fn func() (any, error)) (any, error) {c, done := g.createCall(key)if done {return c.val, c.err}g.makeCall(c, key, fn)return c.val, c.err
}
首先调g.createCall(key)创建call
如果此时已经有其他协程发起了对call的请求,当前协程就阻塞住,等待拿到结果后直接返回
如果done为false,表示当前协程是第一个发起 call 的协程,那执行g.makeCall(c, key, fn)发起真正的call请求

createCall实现如下:
func (g *flightGroup) createCall(key string) (c *call, done bool) {g.lock.Lock()if c, ok := g.calls[key]; ok {g.lock.Unlock()c.wg.Wait()return c, true}c = new(call)c.wg.Add(1)g.calls[key] = cg.lock.Unlock()return c, false
}
- 其实就干了一件事:判断是不是第一个对key的调用
-
- 不是:阻塞在c.wa上
- 是:创建call
接下来看makeCall:
func (g *flightGroup) makeCall(c *call, key string, fn func() (any, error)) {defer func() {g.lock.Lock()delete(g.calls, key)g.lock.Unlock()c.wg.Done()}()c.val, c.err = fn()
}
真正执行fn方法,执行完毕后:
- 将key从calls中删除,这样下一组并发请求到来时,会重新发起真正的请求,获取新值
- 调用wg.done(),这样之前阻塞在wg的协程都会获得结果,并返回
官方库
接下来看看go官方库对singleflight的实现
代码地址:https://cs.opensource.google/go/x/sync/+/036812b2:singleflight/singleflight.go
除了也实现了go-zero的Do方法外,官方库另外提供了DoChan的模式:
- 无论是第一个还是非第一个协程,都不阻塞在DoChan的调用中,而是返回一个channel,可以当需要读数据时才从channel中获取
- 也就是说将是否阻塞获取调用结果的权力交给调用方
看看详细过程:DoChan
func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {ch := make(chan Result, 1)g.mu.Lock()if g.m == nil {g.m = make(map[string]*call)}if c, ok := g.m[key]; ok {c.dups++c.chans = append(c.chans, ch)g.mu.Unlock()// 返回channelreturn ch}c := &call{chans: []chan<- Result{ch}}c.wg.Add(1)g.m[key] = cg.mu.Unlock()// 异步发起调用go g.doCall(c, key, fn)// 非阻塞的返回channelreturn ch
}
那什么时候往channel塞数据呢?在doCall调用成功后,将返回值挨个发送到等待的channel中
for _, ch := range c.chans {ch <- Result{c.val, c.err, c.dups > 0}
}
相关文章:
go并发编程 —— singleflight设计模式
什么是singleflight singleflight是一种并发编程设计模式,将同一时刻的多个并发请求合并成一个请求,以减少对下游服务的压力 为什么叫singleflight fly可以理解为请求数,singleflight就是单个请求 使用场景 该模式主要用于防止缓存击穿 …...
【LeetCode】二叉树的中序遍历(递归,迭代,Morris遍历)
目录 题目要求:给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。 方法一:递归 方法二:迭代 思路分析: 复杂度分析 代码展示: 方法三:Morris 遍历 思路分析: 复杂度分析…...
银行数字化转型导师坚鹏:数字化转型背景下的银行柜员提升之道
数字化转型背景下的银行柜员提升之道 课程背景: 很多银行都在开展银行数字化运营工作,目前存在以下问题急需解决: l 不清楚银行数字化运营包括哪些关键工作? l 不清楚银行数字化运营工作的核心方法论? l 不清楚银行数字…...
ChatGPT的平替来了?一文总结 ChatGPT 的开源平替,你值得拥有
文章目录【AIGC精选】总结 ChatGPT 的开源平替,你值得拥有1.斯坦福发布 Alpaca 7B,性能匹敌 GPT-3.52.弥补斯坦福 Alpaca 中文短板,中文大模型 BELLE 开源3.国产AI大模型 ChatGLM-6B 开启内测4.中文 Alpaca 模型 Luotuo 开源5. ChatGPT 最强竞…...
关于数据同步工具DataX部署
1.DataX简介 1.1 DataX概述 DataX 是阿里巴巴开源的一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 源码地址:GitHub - alibaba/DataX: DataX是…...
如何开发JetBrains插件
1 标题安装 IntelliJ IDEA 如果您还没有安装 IntelliJ IDEA,从官方网站下载并安装 IntelliJ IDEA Community Edition(免费)或 Ultimate Edition(付费)。 2 创建插件项目 在 IntelliJ IDEA 中,创建一个新…...
企业采购成本管理的难题及解决方案
企业采购成本控制是企业管理中的一个重要方面,也是一个不容易解决的难题。企业采购成本控制面临的难题包括以下几个方面: 1、采购流程复杂 企业采购通常需要经过一系列的流程,包括采购计划、采购申请、报价、比价、议标、合同签订、验收、付…...
龙蜥白皮书精选:基于 SM4 算法的文件加密(fscrypt)实践
文/张天佳 通常我们会以文件作为数据载体,使用磁盘,USB 闪存,SD 卡等存储介质进行数据存储,即便数据已经离线存储,仍然不能保证该存储介质不会丢失,如果丢失那么对于我们来说有可能是灾难性的事件。因此对…...
【SpringBoot入门】SpringBoot的配置
SpringBoot的配置文件一、SpringBoot配置文件分类二、yaml 概述三、多环境配置四、Value 和 ConfigurationProperties五、总结一、SpringBoot配置文件分类 SpringBoot 是基于约定的,很多配置都是默认的(主方法上SpringBootApplication注解的子注解Enabl…...
react 学习整理
如何使用引号传递字符串 常见的 <imgclassName avatersrc http://...alt gregorio y />或者声明变量来保存 export default function XXX(){ const avator avator const description gergorio y return (<image className XXXsrc {avator}alt {alt} />)…...
物理引擎系统-ode
物理引擎系统-ode 目录 物理引擎系统-ode 一、物理引擎系统-ode——processIslands 二、物理引擎系统-ode——processIslands 三、物理引擎系统-ode——processIslands 四、物理引擎系统-ode——processIslands 五、物理引擎系统-ode——processIslands 一、物理引…...
函数设计—参数规则
【规则1-1】参数的书写要完整,不要贪图省事只写参数的类型而省略参数名字。 如果函数没有参数,则用 void 填充。 例如: void SetValue(int width, int height); // 良好的风格 void SetValue(int, int); // 不良的风格 float GetValue(…...
rsync远程同步
目录 rsync rsync简介 rsync优点 同步方式 rsync名词解释 rsync工作原理 常用rsync命令 配置源的两种表达方法 远程同步实操 如何不想每次登录的时候输入密码 同步删除文件 定时完成操作 格式二 指定资源下载到/opt进行备份 通过信道协议同步数据编辑编辑 rs…...
中国大陆IP段(仅大陆地区)【2020-07-24】
中国大陆IP段(仅大陆地区)【2020-07-24】 1.1.8.0/24 1.2.4.0/24 1.8.1.0/24 1.8.8.0/24 1.18.128.0/24 1.24.0.0/13 1.45.0.0/16 1.48.0.0/14 1.56.0.0/13 1.68.0.0/14 1.80.0.0/13 1.88.0.0/14 1.92.0.0/20 1.93.0.0/16 1.94.0.0/15 1.119.0.0/17 1.11…...
从零开始的嵌入式Linux生活(一) 背景介绍
文章目录前言本系列文章的主要思想:本系列文章包括:一、什么是嵌入式开发二.嵌入式开发 - 由便宜到贵三.嵌入式开发的基本原理一个美好的假设:再来一个美好的假设美好的假设被打破了 - RTOS系统美好的假设又被打破了 - 嵌入式Linux系统老板飘…...
后缀为whl的文件是什么?如何安装whl文件?学习一下(22)
小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 欢迎和猫妹一起,趣味学Python。 今日主题 了解并使用Pyhton的库安装包文件whl。 什么是whl文件 whl格式本质上是一个压缩包,里面包含了py文件&am…...
整合Juit
整合Juit 1.SpringBoot整合Juit SpringBootTest class Springboot04JuitApplicationTests {AutowiredBookDao bookDao;Testvoid contextLoads() {System.out.println("test................");bookDao.save();} } 名称:SpringBootTest 类型&…...
C#,码海拾贝(11)——拉格朗日(Lagrange)三点式曲面插值算法,《C#数值计算算法编程》源代码升级改进版
本文开始是曲面插值(Surface Interpolation,也称作:二维插值,二元插值)。 数值计算三点式 数值计算三点式是一种常见的数值计算方法,它是通过对已知函数在某个点及其左右两个点处的函数值进行数值插值&…...
CentOS7系统安装MySQL 5.7
目录一、官网下载mysql5.7二、检查mysql依赖环境三、安装MySQL 5.7.281.将安装程序拷贝到/opt目录下2.安装四个安装包3.查看mysql版本4.服务的初始化5.启动mysql,并查看状态(加不加.service后缀都可以)6.查看mysql服务是否自启动(默认自启动)…...
基于粒子群算法优化BP神经网络的高炉si预测,PSO-BP
目录 摘要 BP神经网络的原理 BP神经网络的定义 BP神经网络的基本结构 BP神经网络的神经元 BP神经网络的激活函数, BP神经网络的传递函数 粒子群算法的原理及步骤 基于粒子群算法改进优化BP神经网络的用电量预测 代码 效果图 结果分析 展望 参考 摘要 一般用启发式算法改进B…...
Proteus 8实战:手把手教你搭建ATmega16流水灯仿真,并联动真实代码调试
Proteus 8实战:从零构建ATmega16流水灯仿真系统 在嵌入式开发的学习路径上,仿真工具的价值常常被低估。许多开发者习惯直接上手物理硬件,却在遇到问题时陷入漫长的调试循环。Proteus 8提供的虚拟实验室环境,恰好填补了从理论到实践…...
Starry Night Art Gallery效果展示:黄金渐变按钮交互+实时生成反馈
Starry Night Art Gallery效果展示:黄金渐变按钮交互实时生成反馈 1. 沉浸式艺术体验:当AI遇见文艺复兴 想象一下,你走进的不是一个冰冷的AI工具界面,而是一座数字艺术殿堂。四周是深邃的墨蓝色背景,如同梵高笔下的夜…...
终极指南:NanoVG渲染管线深度解析与抗锯齿技术实战
终极指南:NanoVG渲染管线深度解析与抗锯齿技术实战 【免费下载链接】nanovg Antialiased 2D vector drawing library on top of OpenGL for UI and visualizations. 项目地址: https://gitcode.com/gh_mirrors/na/nanovg NanoVG是一款基于OpenGL的轻量级抗锯…...
2026年Java面试最常被问的1000道题目及参考答案
Java学到什么程度可以面试工作? 要达到能够面试Java开发工作的水平,需要掌握以下几个方面的知识和技能: 1. 基础扎实:熟悉Java语法、面向对象编程概念、异常处理、I/O流等基础知识。这是所有Java开发者必备的基础,也…...
OpenCV实战:3种图像降噪滤波器的Python代码对比(附效果图)
OpenCV实战:3种图像降噪滤波器的Python代码对比(附效果图) 在数字图像处理中,噪声是影响图像质量的主要因素之一。无论是来自传感器的不完美,还是传输过程中的干扰,噪声都会降低图像的清晰度和可用性。对于…...
如何用Python免费下载B站4K大会员视频:bilibili-downloader完整指南
如何用Python免费下载B站4K大会员视频:bilibili-downloader完整指南 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 还在为…...
联想新品入局,AI智能终端市场格局生变
联想新品发布,直击Mac mini“养虾”痛点2026年3月31日,联想集团正式发布YOGA AI Mini与Think AI Tiny两款AI原生智能终端。其中,YOGA AI Mini面向个人消费市场,精准对标当下被众多用户用于运行OpenClaw的Mac mini。Mac mini虽因便…...
DMA传输效率翻倍秘籍:深入解析Burst/Transfer模式在TMS320系列DSP中的配置陷阱
DMA传输效率翻倍秘籍:深入解析Burst/Transfer模式在TMS320系列DSP中的配置陷阱 实时信号处理系统的性能瓶颈往往出现在数据传输环节。当工程师面对高速ADC采集的海量数据时,DMA控制器的高效配置直接决定了系统能否实现理论上的吞吐量。本文将深入剖析TMS…...
AI数字人开源方案:Duix.Avatar本地化部署与应用指南
AI数字人开源方案:Duix.Avatar本地化部署与应用指南 【免费下载链接】Duix-Avatar 🚀 Truly open-source AI avatar(digital human) toolkit for offline video generation and digital human cloning. 项目地址: https://gitcode.com/GitHub_Trending…...
轻量级PDF阅读器SumatraPDF核心功能与效率提升指南
轻量级PDF阅读器SumatraPDF核心功能与效率提升指南 【免费下载链接】sumatrapdf SumatraPDF reader 项目地址: https://gitcode.com/gh_mirrors/su/sumatrapdf 在数字文档处理领域,速度与资源占用往往难以平衡。SumatraPDF以其独特的轻量级设计,重…...
