当前位置: 首页 > article >正文

Go语言中的并发模式:从WaitGroup到errgroup

Go语言中的并发模式从WaitGroup到errgroup作为一个写了十几年代码的Go后端老兵我深刻体会到并发编程的重要性。Go语言以其简洁的并发模型著称通过goroutine和channel我们可以轻松实现高效的并发程序。今天咱们就聊聊Go语言中的并发模式从WaitGroup到errgroup帮助你写出更健壮的并发代码。基本并发原语1. WaitGroupsync.WaitGroup是Go语言中最基础的并发同步原语用于等待一组goroutine完成。import ( fmt sync time ) func main() { var wg sync.WaitGroup for i : 0; i 5; i { wg.Add(1) // 增加计数器 go func(id int) { defer wg.Done() // 减少计数器 fmt.Printf(Goroutine %d started\n, id) time.Sleep(time.Second) fmt.Printf(Goroutine %d finished\n, id) }(i) } wg.Wait() // 等待所有goroutine完成 fmt.Println(All goroutines finished) }2. Mutexsync.Mutex用于保护共享资源防止并发访问导致的数据竞争。import ( fmt sync time ) var ( counter int mutex sync.Mutex ) func main() { var wg sync.WaitGroup for i : 0; i 1000; i { wg.Add(1) go func() { defer wg.Done() mutex.Lock() defer mutex.Unlock() counter }() } wg.Wait() fmt.Println(Counter:, counter) }3. RWMutexsync.RWMutex是读写锁允许多个读操作同时进行但写操作是互斥的。import ( fmt sync time ) var ( data make(map[string]string) rwMutex sync.RWMutex ) func readData(key string) string { rwMutex.RLock() defer rwMutex.RUnlock() return data[key] } func writeData(key, value string) { rwMutex.Lock() defer rwMutex.Unlock() data[key] value } func main() { // 写入数据 writeData(name, Alice) var wg sync.WaitGroup // 多个读操作 for i : 0; i 10; i { wg.Add(1) go func(id int) { defer wg.Done() fmt.Printf(Reader %d: %s\n, id, readData(name)) }(i) } // 一个写操作 wg.Add(1) go func() { defer wg.Done() time.Sleep(time.Millisecond * 100) writeData(name, Bob) fmt.Println(Writer: Updated name to Bob) }() wg.Wait() fmt.Println(Final data:, data[name]) }高级并发模式1. errgrouperrgroup是Go 1.7引入的包用于管理一组goroutine并处理错误。import ( context fmt net/http golang.org/x/sync/errgroup ) func main() { g, ctx : errgroup.WithContext(context.Background()) urls : []string{ https://example.com, https://golang.org, https://invalid-url, } for _, url : range urls { url : url // 捕获循环变量 g.Go(func() error { req, err : http.NewRequest(GET, url, nil) if err ! nil { return err } req req.WithContext(ctx) resp, err : http.DefaultClient.Do(req) if err ! nil { return err } defer resp.Body.Close() fmt.Printf(%s: %d\n, url, resp.StatusCode) return nil }) } if err : g.Wait(); err ! nil { fmt.Printf(Error: %v\n, err) } else { fmt.Println(All requests completed successfully) } }2. Oncesync.Once用于确保某个函数只执行一次。import ( fmt sync ) var ( once sync.Once instance *Database ) type Database struct { // 数据库连接 } func GetDatabase() *Database { once.Do(func() { instance Database{} fmt.Println(Database initialized) }) return instance } func main() { var wg sync.WaitGroup for i : 0; i 10; i { wg.Add(1) go func() { defer wg.Done() db : GetDatabase() fmt.Printf(Database instance: %p\n, db) }() } wg.Wait() }3. Poolsync.Pool用于对象复用减少内存分配和GC压力。import ( fmt sync ) var bufferPool sync.Pool{ New: func() interface{} { fmt.Println(Creating new buffer) return make([]byte, 1024) }, } func main() { var wg sync.WaitGroup for i : 0; i 5; i { wg.Add(1) go func(id int) { defer wg.Done() buf : bufferPool.Get().([]byte) defer bufferPool.Put(buf) fmt.Printf(Goroutine %d: Using buffer %p\n, id, buf) }(i) } wg.Wait() // 再次使用 buf : bufferPool.Get().([]byte) fmt.Printf(Main: Using buffer %p\n, buf) bufferPool.Put(buf) }实用并发模式1. 工作池模式工作池模式用于限制并发数量避免创建过多goroutine。import ( fmt sync time ) func worker(id int, jobs -chan int, results chan- int) { for job : range jobs { fmt.Printf(Worker %d processing job %d\n, id, job) time.Sleep(time.Second) results - job * 2 } } func main() { const ( numWorkers 3 numJobs 10 ) jobs : make(chan int, numJobs) results : make(chan int, numJobs) // 启动工作池 var wg sync.WaitGroup for i : 1; i numWorkers; i { wg.Add(1) go func(id int) { defer wg.Done() worker(id, jobs, results) }(i) } // 发送任务 for i : 1; i numJobs; i { jobs - i } close(jobs) // 收集结果 go func() { wg.Wait() close(results) }() for result : range results { fmt.Printf(Result: %d\n, result) } }2. 扇入扇出模式扇入扇出模式用于处理多个输入合并为一个输出。import ( fmt sync time ) func producer(id int, out chan- int) { for i : 0; i 5; i { value : id*10 i fmt.Printf(Producer %d: %d\n, id, value) out - value time.Sleep(time.Millisecond * 100) } } func fanIn(inputs ...-chan int) -chan int { out : make(chan int) var wg sync.WaitGroup for _, input : range inputs { wg.Add(1) go func(ch -chan int) { defer wg.Done() for value : range ch { out - value } }(input) } go func() { wg.Wait() close(out) }() return out } func main() { ch1 : make(chan int) ch2 : make(chan int) ch3 : make(chan int) // 启动生产者 go producer(1, ch1) go producer(2, ch2) go producer(3, ch3) // 扇入 merged : fanIn(ch1, ch2, ch3) // 消费结果 for value : range merged { fmt.Printf(Consumer: %d\n, value) } }3. 超时控制模式超时控制模式用于防止goroutine无限阻塞。import ( context fmt time ) func main() { ctx, cancel : context.WithTimeout(context.Background(), 2*time.Second) defer cancel() resultCh : make(chan string) go func() { time.Sleep(3 * time.Second) // 模拟长时间操作 resultCh - Operation completed }() select { case result : -resultCh: fmt.Println(Result:, result) case -ctx.Done(): fmt.Println(Operation timed out) } }并发最佳实践限制并发数量使用工作池模式限制并发goroutine数量避免系统资源耗尽。使用context管理生命周期使用context.Context来管理goroutine的生命周期支持取消和超时。避免数据竞争使用Mutex、RWMutex或channel来保护共享资源。处理错误使用errgroup来管理一组goroutine的错误。优雅关闭确保所有goroutine都能正常关闭避免泄漏。使用原子操作对于简单的计数器等操作使用sync/atomic包提高性能。避免死锁注意goroutine之间的依赖关系避免循环等待。测试并发代码使用-race标志运行测试检测数据竞争。实战案例并发下载文件import ( context fmt io net/http os path/filepath golang.org/x/sync/errgroup ) func downloadFile(ctx context.Context, url string, outputDir string) error { req, err : http.NewRequest(GET, url, nil) if err ! nil { return err } req req.WithContext(ctx) resp, err : http.DefaultClient.Do(req) if err ! nil { return err } defer resp.Body.Close() if resp.StatusCode ! http.StatusOK { return fmt.Errorf(bad status: %s, resp.Status) } filename : filepath.Base(url) filepath : filepath.Join(outputDir, filename) file, err : os.Create(filepath) if err ! nil { return err } defer file.Close() _, err io.Copy(file, resp.Body) if err ! nil { return err } fmt.Printf(Downloaded %s to %s\n, url, filepath) return nil } func main() { urls : []string{ https://example.com, https://golang.org, https://github.com, } outputDir : ./downloads if err : os.MkdirAll(outputDir, 0755); err ! nil { fmt.Println(Error creating output directory:, err) return } g, ctx : errgroup.WithContext(context.Background()) for _, url : range urls { url : url // 捕获循环变量 g.Go(func() error { return downloadFile(ctx, url, outputDir) }) } if err : g.Wait(); err ! nil { fmt.Println(Error:, err) } else { fmt.Println(All downloads completed successfully) } }总结并发编程是Go语言的核心特性之一通过掌握各种并发模式我们可以写出更高效、更健壮的并发代码。从基础的WaitGroup到高级的errgroup从工作池模式到扇入扇出模式Go语言提供了丰富的并发工具和模式。记住并发编程需要谨慎处理要注意避免数据竞争、死锁等问题。希望本文能帮助你在Go语言项目中更好地应用并发模式构建更高效的应用程序。

相关文章:

Go语言中的并发模式:从WaitGroup到errgroup

Go语言中的并发模式:从WaitGroup到errgroup 作为一个写了十几年代码的Go后端老兵,我深刻体会到并发编程的重要性。Go语言以其简洁的并发模型著称,通过goroutine和channel,我们可以轻松实现高效的并发程序。今天咱们就聊聊Go语言中…...

RPCS3游戏汉化实战指南:从零构建多语言游戏体验

RPCS3游戏汉化实战指南:从零构建多语言游戏体验 【免费下载链接】rpcs3 PS3 emulator/debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 还在为PS3经典游戏的日文界面而困扰吗?通过RPCS3模拟器的强大补丁系统,您可以…...

FlowState Lab创意作品展:从音乐旋律到光影变化的波动艺术

FlowState Lab创意作品展:从音乐旋律到光影变化的波动艺术 1. 波动艺术的新维度 当数据不再只是冰冷的数字,而是化作跳动的音符、流动的光影和变幻的图形,这就是FlowState Lab带来的创意革命。我们最近完成了一系列跨媒介艺术实验&#xff…...

nli-distilroberta-base在数据库智能查询中的应用:自然语言转SQL实战

nli-distilroberta-base在数据库智能查询中的应用:自然语言转SQL实战 1. 引言:当自然语言遇上数据库查询 "帮我找出上个月销售额超过10万的产品"——这样的需求如果能让数据库直接理解该多好?传统SQL查询需要专业技术人员编写复杂…...

Linux服务器无GPU也能跑!Ollama部署DeepSeek-R1模型存储路径自定义与性能调优指南

Linux服务器无GPU高效部署DeepSeek-R1模型全攻略:从存储路径优化到性能调优 当你在云服务器或老旧设备上尝试运行AI模型时,是否经常遇到存储空间不足或性能低下的困扰?本文将带你深入探索如何在无GPU的Linux环境中,通过Ollama高效…...

别再只盯着ONNX了!用PNNX把PyTorch模型轻松转成ncnn格式(安卓部署实战)

深度学习模型安卓部署实战:PNNX与ONNX转换工具深度对比 在移动端部署深度学习模型时,模型转换环节往往是开发者遇到的第一个技术瓶颈。许多团队习惯性地选择ONNX作为中间格式,却忽视了更高效的替代方案。本文将带您深入探索PNNX这一专为PyTor…...

nRF52832上电启动全解析:从MBR到Bootloader的跳转机制与寄存器配置

nRF52832上电启动全解析:从MBR到Bootloader的跳转机制与寄存器配置 当nRF52832芯片通电瞬间,一场精密的硬件芭蕾在微秒级时间内悄然上演。这颗蓝牙低功耗SoC的启动流程远非简单的"通电即运行",而是涉及存储器分区、寄存器配置和多重…...

Sparse Sinkhorn Attention:点云处理中的高效全局注意力机制

1. 什么是Sparse Sinkhorn Attention? 如果你玩过乐高积木,应该知道把一堆零散的积木块拼成完整模型的过程。点云数据处理就像这个拼积木的过程——我们需要从成千上万个三维坐标点中识别出物体的结构和特征。传统方法就像只用相邻积木块拼装&#xff0c…...

OpenPose终极指南:10分钟掌握人体姿态估计核心技术

OpenPose终极指南:10分钟掌握人体姿态估计核心技术 【免费下载链接】openpose 项目地址: https://gitcode.com/gh_mirrors/op/openpose 想要快速搭建专业级的人体姿态识别系统吗?OpenPose作为业界领先的开源姿态估计库,能够实时检测图…...

告别官方驱动:深入解读ES7210寄存器,打造你自己的ESP32音频采集库

告别官方驱动:深入解读ES7210寄存器,打造你自己的ESP32音频采集库 在嵌入式音频开发领域,ES7210作为一款高性能多通道麦克风ADC芯片,因其出色的信噪比和灵活的配置选项,成为ESP32平台上音频采集的热门选择。然而&#…...

探索式学习:UMA模型在水分解催化中的应用指南

探索式学习:UMA模型在水分解催化中的应用指南 【免费下载链接】ocp Open Catalyst Projects library of machine learning methods for catalysis 项目地址: https://gitcode.com/GitHub_Trending/oc/ocp 突破传统计算瓶颈:UMA模型的核心价值解析…...

OpenClaw+nanobot自动化测试:24小时监控网站可用性

OpenClawnanobot自动化测试:24小时监控网站可用性 1. 为什么需要自动化网站监控 作为个人站长,我经常遇到这样的困扰:半夜网站突然宕机,直到第二天收到用户反馈才发现问题。传统监控方案要么价格昂贵,要么配置复杂&a…...

从零开始:3小时掌握Arduino ESP32开发板完整安装与配置指南 [特殊字符]

从零开始:3小时掌握Arduino ESP32开发板完整安装与配置指南 🚀 【免费下载链接】arduino-esp32 Arduino core for the ESP32 项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32 想要快速上手ESP32物联网开发吗?无论你是…...

智能配置引擎如何攻克AMD黑苹果的三大技术壁垒

智能配置引擎如何攻克AMD黑苹果的三大技术壁垒 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 在黑苹果领域,AMD平台曾被视为技术禁区&…...

StructBERT文本相似度模型在互联网内容治理中的应用:重复与低质内容识别

StructBERT文本相似度模型在互联网内容治理中的应用:重复与低质内容识别 你有没有遇到过这样的情况?打开一个内容平台,满屏都是大同小异的文章,或者点开几篇帖子,发现内容似曾相识,只是换了几个词。对于平…...

解决B站视频收藏难题的8K超清下载解决方案:Bilidown全解析

解决B站视频收藏难题的8K超清下载解决方案:Bilidown全解析 【免费下载链接】bilidown 哔哩哔哩视频解析下载工具,支持 8K 视频、Hi-Res 音频、杜比视界下载、批量解析,可扫码登录,常驻托盘。 项目地址: https://gitcode.com/gh_…...

Notepad--终极指南:5分钟掌握国产跨平台文本编辑器的完整解决方案

Notepad--终极指南:5分钟掌握国产跨平台文本编辑器的完整解决方案 【免费下载链接】notepad-- 一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。 项目地址: https://gitcode.com/GitHub_Trending/no/notepad-…...

Cataclysm: Dark Days Ahead - 在末日废土中生存的终极指南

Cataclysm: Dark Days Ahead - 在末日废土中生存的终极指南 【免费下载链接】Cataclysm-DDA Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world. 项目地址: https://gitcode.com/GitHub_Trending/ca/Cataclysm-DDA 欢迎来到Cat…...

如何高效解决Calibre中文路径翻译问题:完整实用指南

如何高效解决Calibre中文路径翻译问题:完整实用指南 【免费下载链接】calibre-do-not-translate-my-path Switch my calibre library from ascii path to plain Unicode path. 将我的书库从拼音目录切换至非纯英文(中文)命名 项目地址: htt…...

从Proteus仿真到普中开发板烧录:51单片机抢答器完整开发流程避坑指南

从Proteus仿真到普中开发板烧录:51单片机抢答器完整开发流程避坑指南 在电子设计的学习道路上,51单片机项目开发是一个经典的入门实践。抢答器作为典型的互动式电子系统,涵盖了输入检测、逻辑控制、显示输出等核心知识点,是检验学…...

别只把Text2SQL当玩具:结合Spring AI与DeepSeek,我们这样用它优化了内部报表系统

别只把Text2SQL当玩具:结合Spring AI与DeepSeek,我们这样用它优化了内部报表系统 当业务团队每天提出十几个动态报表需求时,传统开发模式就像用勺子舀干涸的井水——我们团队曾连续三个月被SQL编写和接口开发压得喘不过气。直到将Text2SQL技术…...

Hunyuan3D-2:AI驱动3D创作的4大技术突破

Hunyuan3D-2:AI驱动3D创作的4大技术突破 【免费下载链接】Hunyuan3D-2 High-Resolution 3D Assets Generation with Large Scale Hunyuan3D Diffusion Models. 项目地址: https://gitcode.com/GitHub_Trending/hu/Hunyuan3D-2 Hunyuan3D-2是一款基于大规模扩…...

实战指南:如何用PyMC实现贝叶斯分位数回归解决业务预测难题

实战指南:如何用PyMC实现贝叶斯分位数回归解决业务预测难题 【免费下载链接】pymc Python 中的贝叶斯建模和概率编程。 项目地址: https://gitcode.com/GitHub_Trending/py/pymc 你是否曾面临这样的困境:使用传统线性回归预测客户流失率&#xff…...

告别SD卡!用ADB在Windows PowerShell里给开发板传文件,保姆级避坑指南

告别SD卡!用ADB在Windows PowerShell里给开发板传文件,保姆级避坑指南 嵌入式开发中,文件传输一直是个高频痛点。每次修改代码后,传统方式要么拔出SD卡用读卡器拷贝,要么搭建FTP/NFS网络共享,不仅步骤繁琐…...

RWKV7-1.5B-g1a开源模型优势:无依赖离线加载+低维护成本

RWKV7-1.5B-g1a开源模型优势:无依赖离线加载低维护成本 1. 模型简介 rwkv7-1.5B-g1a 是基于新一代 RWKV-7 架构的开源文本生成模型,专为轻量级应用场景设计。这个1.5B参数的模型在多语言处理上表现出色,特别适合以下场景: 基础问…...

3分钟,零代码!让Arduino看懂你的手势——Teachable Machine硬件魔法揭秘

3分钟,零代码!让Arduino看懂你的手势——Teachable Machine硬件魔法揭秘 【免费下载链接】teachablemachine-community Example code snippets and machine learning code for Teachable Machine 项目地址: https://gitcode.com/gh_mirrors/te/teachab…...

TouchGal Galgame社区终极指南:一站式游戏资源管理与交流平台

TouchGal Galgame社区终极指南:一站式游戏资源管理与交流平台 【免费下载链接】kun-touchgal-next TouchGAL是立足于分享快乐的一站式Galgame文化社区, 为Gal爱好者提供一片净土! 项目地址: https://gitcode.com/gh_mirrors/ku/kun-touchgal-next 还在为寻找…...

M2LOrder模型Mathtype公式编辑器的趣味扩展:为数学证明添加情感注释

M2LOrder模型Mathtype公式编辑器的趣味扩展:为数学证明添加情感注释 你有没有过这样的经历?面对一篇复杂的数学论文或教材,读到某个证明步骤时,心里忍不住嘀咕:“这一步也太巧妙了,怎么想到的?…...

Maestro移动测试自动化成长路径:从零基础到专家的完整技能图谱

Maestro移动测试自动化成长路径:从零基础到专家的完整技能图谱 【免费下载链接】maestro Painless Mobile UI Automation 项目地址: https://gitcode.com/GitHub_Trending/ma/maestro 想要构建可靠的移动应用测试体系却不知从何开始?Maestro移动测…...

我把DeepSeek调教成了我的‘专属文案总监’:角色扮演Prompt的实战配置手册

把DeepSeek调教成你的「专属文案总监」:高阶Prompt工程实战指南 当市场部的Lisa第一次用AI生成产品文案时,她得到的是一篇充满技术术语的说明文;而运营总监Mike让AI写的周报,读起来像学术论文。这就像给米其林大厨一台高级烤箱&a…...