Go conc库学习与使用
文章目录
- 主要功能和特点
- `conc` 的安装
- 典型使用场景
- 示例代码
- 并行执行多个 Goroutines
- 错误处理
- 限制并发 Goroutines 数量
- 使用 `context.Context` 进行任务控制
- 常见问题
- 1. **任务中发生 `panic`**
- 原因:
- 解决方法:
- 2. **`conc.Group` 重复调用 `Wait()`**
- 原因:
- 解决方法:
- 3. **在 `Wait()` 之前修改任务**
- 原因:
- 解决方法:
- 4. **`context` 被取消或超时导致的 `panic`**
- 原因:
- 解决方法:
- 5. **并发访问共享资源引发的 `panic`**
- 原因:
- 解决方法:
- 学习与使用建议
- 总结
sourcegraph/conc 是由 Sourcegraph 开发的并发控制库,用于 Go 语言中更方便地管理和协调 Goroutines。
conc 旨在简化 Go 并发编程,提供更直观的 API 来处理并发操作,尤其是 Goroutines 的生命周期管理、错误处理以及资源安全访问。
主要功能和特点
-
Group 协调 Goroutines:
conc提供了一种GroupAPI,可以帮助管理多个 Goroutines 的并行执行,类似于sync.WaitGroup,但提供了更多的高级特性,例如错误处理和结果收集。
-
并发任务控制:
conc的Group可以控制任务的并发度,确保不会过多创建 Goroutines,避免过度并发导致系统压力。
-
自动错误处理和结果收集:
conc提供了内置的错误处理机制,每个 Goroutine 的错误都能被安全地收集到,避免了 Go 中手动编写错误通道的麻烦。同时,conc还可以收集并发任务的返回结果。
-
上下文支持:
conc可以与context.Context一起使用,支持超时、取消等控制。
-
简洁易用:
- 与 Go 标准库相比,
conc提供了简洁且易用的 API,降低了并发编程的复杂性。
- 与 Go 标准库相比,
conc 的安装
可以通过 go get 来安装 conc 库:
go get github.com/sourcegraph/conc
典型使用场景
-
并行执行多个 Goroutines 并等待它们完成:
使用conc.Group来管理多个 Goroutine,可以确保主 Goroutine 等待所有并发任务完成。 -
错误收集和处理:
可以自动收集并发 Goroutines 中的错误,并提供一个统一的处理机制。 -
限制并发数:
控制 Goroutines 的并发数量,防止系统过载。
示例代码
并行执行多个 Goroutines
这是一个简单的示例,演示如何使用 conc.Group 来并行执行多个 Goroutines:
package mainimport ("context""fmt""log""time""github.com/sourcegraph/conc"
)func main() {// 创建一个 conc.Group 来管理并发任务var group conc.Group// 添加多个并发任务for i := 0; i < 5; i++ {i := i // 避免闭包引用问题group.Go(func() {// 模拟一些工作time.Sleep(time.Duration(i) * time.Second)fmt.Printf("Task %d completed\n", i)})}// 等待所有任务完成if err := group.Wait(); err != nil {log.Fatalf("Error occurred: %v", err)}fmt.Println("All tasks completed")
}
错误处理
如果 Goroutines 可能返回错误,conc.Group 提供了错误收集功能:
package mainimport ("errors""fmt""log""time""github.com/sourcegraph/conc"
)func main() {var group conc.Group// 向 group 添加多个并发任务,其中某个任务会返回错误for i := 0; i < 5; i++ {i := igroup.Go(func() error {time.Sleep(time.Duration(i) * time.Second)if i == 3 {return errors.New("error in task 3")}fmt.Printf("Task %d completed\n", i)return nil})}// 等待所有任务完成,并捕获错误if err := group.Wait(); err != nil {log.Fatalf("Error occurred: %v", err)}fmt.Println("All tasks completed successfully")
}
限制并发 Goroutines 数量
通过 conc.LimitedGroup,可以限制同时运行的 Goroutines 数量:
package mainimport ("context""fmt""log""time""github.com/sourcegraph/conc"
)func main() {// 创建一个 LimitedGroup,限制并发 Goroutines 的数量为 3group := conc.NewLimitedGroup(3)// 添加多个并发任务for i := 0; i < 10; i++ {i := igroup.Go(func() {// 模拟一些工作time.Sleep(time.Second)fmt.Printf("Task %d completed\n", i)})}// 等待所有任务完成if err := group.Wait(); err != nil {log.Fatalf("Error occurred: %v", err)}fmt.Println("All tasks completed")
}
在这个例子中,即使我们添加了 10 个 Goroutines,实际上只有 3 个任务会同时执行,其余任务会等待前面的任务完成后再继续执行。
使用 context.Context 进行任务控制
conc.Group 支持与 context.Context 一起使用,可以处理任务的超时和取消操作:
package mainimport ("context""fmt""log""time""github.com/sourcegraph/conc"
)func main() {// 创建一个带有超时的 contextctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)defer cancel()// 创建一个 conc.Groupvar group conc.Groupgroup.WithContext(ctx)// 添加并发任务for i := 0; i < 5; i++ {i := igroup.Go(func() error {time.Sleep(2 * time.Second)fmt.Printf("Task %d completed\n", i)return nil})}// 等待任务完成或超时if err := group.Wait(); err != nil {log.Fatalf("Error occurred: %v", err)}fmt.Println("All tasks completed or context timed out")
}
如果任务在超时时间内没有完成,则会自动取消未执行完的任务。
常见问题
在使用 sourcegraph/conc 时,虽然库本身已经提供了简化并发编程的 API,并且在设计上避免了一些常见的错误,但仍然有可能会遇到一些 panic 问题。以下是一些可能会遇到的 panic 情况,以及相应的原因和解决方案:
1. 任务中发生 panic
由于 conc.Group 中的每个任务实际上是一个 Goroutine,因此如果某个任务内部发生了 panic,默认情况下整个进程都会终止。这是 Go 语言中的常见现象。如果一个任务中出现了未捕获的运行时错误(如数组越界、空指针引用等),会导致 panic。
原因:
- 任务函数内有运行时错误,例如空指针访问、除零等。
解决方法:
- 在任务中使用
recover来捕获panic,以防止程序崩溃。
示例:
package mainimport ("fmt""log""time""github.com/sourcegraph/conc"
)func main() {var group conc.Groupfor i := 0; i < 3; i++ {i := igroup.Go(func() {defer func() {if r := recover(); r != nil {log.Printf("Recovered from panic in task %d: %v\n", i, r)}}()if i == 2 {// 模拟一个panicpanic("something went wrong")}time.Sleep(time.Second)fmt.Printf("Task %d completed\n", i)})}if err := group.Wait(); err != nil {log.Fatalf("Error occurred: %v", err)}fmt.Println("All tasks completed")
}
在这个示例中,recover() 会捕获任务中的 panic,防止整个程序崩溃。
2. conc.Group 重复调用 Wait()
conc.Group 设计用于管理一组并发 Goroutines,并在调用 Wait() 时阻塞直到所有 Goroutines 完成。如果你尝试多次调用 Wait(),会引发 panic,因为 conc.Group 只能等待 Goroutines 一次。
原因:
- 调用
group.Wait()后,试图再次调用Wait()。
解决方法:
- 确保每个
conc.Group的Wait()只调用一次。如果需要重新启动并发任务,应该创建一个新的conc.Group实例。
示例:
var group conc.Group
group.Go(func() {time.Sleep(time.Second)
})
group.Wait()// 再次调用会触发 panic
// group.Wait() // 不能重复调用 Wait
3. 在 Wait() 之前修改任务
如果你在调用 Wait() 后,试图向 conc.Group 中添加新的任务,可能会引发 panic。这是因为 conc.Group 一旦进入等待状态,就不能再接受新的任务。
原因:
- 在调用
group.Wait()后,继续调用group.Go()添加任务。
解决方法:
- 确保所有任务在调用
Wait()之前都已经添加完毕。如果需要重新添加任务,应该创建一个新的conc.Group。
示例:
package mainimport ("fmt""log""time""github.com/sourcegraph/conc"
)func main() {var group conc.Groupgroup.Go(func() {time.Sleep(time.Second)fmt.Println("Task 1 completed")})if err := group.Wait(); err != nil {log.Fatalf("Error occurred: %v", err)}// 不能在 Wait() 后添加任务,否则会 panic// group.Go(func() { fmt.Println("New Task") })
}
4. context 被取消或超时导致的 panic
在与 context.Context 一起使用时,如果 context 被取消或超时,任务可能会提前终止。如果没有正确处理这种情况,可能会导致 panic,尤其是在任务依赖外部资源或状态时。
原因:
context被取消后,某些任务未能正确处理取消信号,继续执行。
解决方法:
- 在任务中检查
context.Context是否被取消,并正确处理任务的中止。可以通过ctx.Done()来监听context的取消信号。
示例:
package mainimport ("context""fmt""log""time""github.com/sourcegraph/conc"
)func main() {ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)defer cancel()var group conc.Groupgroup.WithContext(ctx)for i := 0; i < 3; i++ {i := igroup.Go(func() error {select {case <-time.After(3 * time.Second): // 任务超时长于 context 超时fmt.Printf("Task %d completed\n", i)case <-ctx.Done(): // 处理 context 取消fmt.Printf("Task %d canceled due to context timeout\n", i)return ctx.Err()}return nil})}if err := group.Wait(); err != nil {log.Printf("Error occurred: %v\n", err)}
}
在这个例子中,当 context 超时时,任务会被正确取消,并不会继续运行。
5. 并发访问共享资源引发的 panic
尽管 conc.Group 本身并不会引发与共享资源相关的 panic,但如果任务中不安全地并发访问共享变量或资源,仍可能导致数据竞争或 panic。
原因:
- 多个 Goroutines 同时访问或修改共享资源而未使用适当的同步机制。
解决方法:
- 使用同步机制(如
sync.Mutex)来保护对共享资源的访问,避免数据竞争。
示例:
package mainimport ("fmt""sync""time""github.com/sourcegraph/conc"
)func main() {var group conc.Groupvar mu sync.Mutex // 保护共享资源count := 0for i := 0; i < 5; i++ {group.Go(func() {time.Sleep(1 * time.Second)mu.Lock() // 锁定共享资源count++mu.Unlock() // 解锁})}group.Wait()fmt.Printf("Final count: %d\n", count)
}
在这个示例中,通过 sync.Mutex 锁定共享资源 count,避免了可能的数据竞争或 panic。
学习与使用建议
- 多线程任务协调:在需要同时执行多个任务时,可以通过
conc.Group轻松管理。 - 错误处理:如果需要捕捉每个 Goroutine 的执行错误,可以利用
conc.Group的内置错误处理机制。 - 并发限制:当系统对并发量有上限时,
conc.LimitedGroup是非常有用的工具,可以帮助控制 Goroutines 数量。 - 与上下文配合:在需要任务超时、取消等场景时,建议结合
context.Context使用。
总结
sourcegraph/conc 是一个简化 Go 并发编程的高效工具库。它提供了比标准库更简洁、更功能丰富的 API,能够更好地处理 Goroutines 的错误、结果以及并发数量控制。同时,它还集成了 context,适合处理超时和取消任务的场景。
sourcegraph/conc 设计简单且安全,但在使用过程中,开发者仍需注意 Goroutines 常见的并发问题。常见的 panic 情况包括任务中的运行时错误、重复调用 Wait()、context 超时、以及不安全的并发访问。通过正确的任务管理、错误处理和同步机制,可以有效避免这些问题。
相关文章:
Go conc库学习与使用
文章目录 主要功能和特点conc 的安装典型使用场景示例代码并行执行多个 Goroutines错误处理限制并发 Goroutines 数量使用 context.Context 进行任务控制 常见问题1. **任务中发生 panic**原因:解决方法: 2. **conc.Group 重复调用 Wait()**原因…...
大模型prompt先关
对于未出现的任务,prompt编写技巧: 1、假设你是资深的摘要生成专家,根据提供的内容,总结对应的摘要信息。请生成一个指令,指令中带有一个使用例子。直接提供给大型模型以执行此任务。 2、基于大模型提供的内容再进行二…...
尚品汇-自动化部署-Jenkins的安装与环境配置(五十六)
目录: 自动化持续集成 (1)环境准备 (2)初始化 Jenkins 插件和管理员用户 (3)工作流程 (4)配置 Jenkins 构建工具 自动化持续集成 互联网软件的开发和发布…...
【尚跑】2024铜川红色照金半程马拉松赛,大爬坡152安全完赛
1、赛事背景 2024年9月22日8点,2024铜川红色照金半程马拉松赛于照金1933广场鸣枪起跑! 起跑仪式上,6000位选手们合唱《歌唱祖国》,熟悉的旋律响彻陕甘边革命根据地照金纪念馆前,激昂的歌声凝聚心中不变的热爱。随着国…...
WPS中让两列数据合并的方法
有这样一个需求,就是把A列数据和B列数据进行合并(空单元格略过)具体实现效果如图下: 该如何操作呢? 首先在新的一列第一个单元格中输入公式"A1&B1" 然后回车,就出现了两列单元格数据合并的效…...
使用yum为centos系统安装软件以及使用(包含阿里云yum源配置)
centos系统配置阿里云yum源 因为centos7官方停止维护,自带yum源用不了了,所以可以更换成阿里云yum源 方法: 使用root权限执行以下语句 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo CentOS…...
《深度学习》【项目】OpenCV 发票识别 透视变换、轮廓检测解析及案例解析
目录 一、透视变换 1、什么是透视变换 2、操作步骤 1)选择透视变换的源图像和目标图像 2)确定透视变换所需的关键点 3)计算透视变换的变换矩阵 4)对源图像进行透视变换 5)对变换后的图像进行插值处理 二、轮廓检测…...
Linux 线程互斥
前言 对于初学线程的伙伴来讲,多线程并发访问导致的数据不一致问题,总是让人陷入怀疑,很多人只是给你说加锁!但没有人告诉你为什么?本篇博客将详解! 目录 前言 一、线程互斥 • 为什么票会出现负数的情…...
【Redis 源码】6AOF持久化
1 AOF功能说明 aof.c 文件是 Redis 中负责 AOF(Append-Only File)持久化的核心文件。AOF 持久化通过记录服务器接收到的每个写命令来实现数据的持久化。这样,在 Redis 重启时,可以通过重放这些命令来恢复数据。 2 AOF相关配置 a…...
6.MySQL基本查询
目录 表的增删查改Insert(插入)插入替换插入替换2 Retrieve(查找)SELECT 列全列查找指定列查询查询字段为表达式为查询结果指定别名结果去重 WHERE 条件order by子句筛选分页结果 Update(更新)delete&#…...
Linux字符设备驱动开发
Linux 字符设备驱动开发是内核模块开发中的一个重要部分,主要用于处理字节流数据设备(如串口、键盘、鼠标等)。字符设备驱动的核心任务是定义如何与用户空间程序交互,通常通过一组文件操作函数进行。这些函数会映射到 open、read、…...
HTML5+JavaScript绘制闪烁的网格错觉
HTML5JavaScript绘制闪烁的网格错觉 闪烁的网格错觉(scintillating grid illusion)是一种视觉错觉,通过简单的黑白方格网格和少量的精心设计,能够使人眼前出现动态变化的效果。 闪烁的栅格错觉,是一种经典的视觉错觉…...
每日OJ题_牛客_拼三角_枚举/DFS_C++_Java
目录 牛客_拼三角_枚举/DFS 题目解析 C代码1 C代码2 Java代码 牛客_拼三角_枚举/DFS 拼三角_枚举/DFS 题目解析 简单枚举,不过有很多种枚举方法,这里直接用简单粗暴的枚举方式。 C代码1 #include <iostream> #include <algorithm> …...
[uni-app]小兔鲜-01项目起步
项目介绍 效果演示 技术架构 创建项目 HBuilderX创建 下载HBuilderX编辑器 HBuilderX/创建项目: 选择模板/选择Vue版本/创建 安装插件: 工具/插件安装/uni-app(Vue3)编译器 vue代码不能直接运行在小程序环境, 编译插件帮助我们进行代码转换 绑定微信开发者工具: 指定微信开…...
安全的价值:构建现代企业的基础
物理安全对于组织来说并不是事后才考虑的问题:它是关键的基础设施。零售商、医疗保健提供商、市政当局、学校和所有其他类型的组织都依赖安全系统来保障其人员和场所的安全。 随着安全技术能力的不断发展,许多组织正在以更广泛的视角看待他们的投资&am…...
门面(外观)模式
简介 门面模式(Facade Pattern)又叫作外观模式,提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构型设计模式。 通用模板 创建子系统角色类…...
kotlin flow 使用
1 创建flow 方式1 通过携程扩展函数FlowKt中的flow扩展函数可以直接构建flow,只需要传递FlowCollector收集器实现类就可以了 private fun create1(){val intFlow createFlow()println("创建int flow: $intFlow")runBlocking {println("开始收集&…...
vue3 实现文本内容超过N行折叠并显示“...展开”组件
1. 实现效果 组件内文字样式取决与外侧定义 组件大小发生变化时,文本仍可以省略到指定行数 文本不超过时, 无展开,收起按钮 传入文本发生改变后, 组件展示新的文本 2. 代码 文件名TextEllipsis.vue <template><div ref"compRef" class"wq-text-ellip…...
根据源码解析Vue2中对于对象的变化侦测
UI render(state) VUE的特点是数据驱动视图,在这里可以把数据理解为状态,而视图就是用户可以看到的页面,页面是动态变化的,而他的变化或是用户操作引起,或是后端数据变化引起,这些都可以说是数据的状态变…...
爬虫技术深潜:探究 JsonPath 与 XPath 的语法海洋与实战岛屿
Python爬虫中JSON与XML字符串的XPath和JsonPath过滤语法区别对比 在信息爆炸的互联网时代,数据抓取成为了获取宝贵信息的关键技能。对于技术爱好者,特别是Python程序员来说,熟练掌握JSON和XML数据解析方法至关重要。本文旨在深入探讨这两种格…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
