方法1

代码

package mainimport ("fmt""sync""time"
)func main() {allChan := make(chan interface{}, 3)var sendWg, recvWg sync.WaitGroup // 分别同步发送和接收// 发送goroutinesendWg.Add(1)go func() {defer sendWg.Done()for i := 0; i < 10; i++ {time.Sleep(time.Millisecond * 10)allChan <- ifmt.Printf("发送: %d\n", i)}close(allChan) // 发送完成后关闭channel}()// 接收goroutinerecvWg.Add(1)go func() {defer recvWg.Done()for item := range allChan {time.Sleep(time.Millisecond * 20) // 模拟处理耗时fmt.Printf("接收: %v\n", item)}}()// 先等待发送完成,再等待接收完成sendWg.Wait()recvWg.Wait()fmt.Println("所有操作完成")
}

运行结果:

标准输出:发送: 0
发送: 1
接收: 0
发送: 2
发送: 3
接收: 1
发送: 4
发送: 5
接收: 2
发送: 6
接收: 3
发送: 7
接收: 4
发送: 8
接收: 5
发送: 9
接收: 6
接收: 7
接收: 8
接收: 9
所有操作完成

分析

优化说明

  1. 双重同步:
  • 使用两个WaitGroup(sendWg和recvWg),分别等待发送和接收 goroutine 完成。
  • 先通过sendWg.Wait()确保所有数据发送完毕并关闭 channel;
  • 再通过recvWg.Wait()确保接收 goroutine 处理完所有数据。
  1. channel 关闭逻辑:
  • 发送完成后关闭 channel 是关键,这会让接收 goroutine 的range循环在取完数据后自动退出,避免接收端阻塞。
  1. 适用场景:
  • 这种 “发送 + 接收都异步” 的模式适合需要主程序同时处理其他逻辑的场景(例如同时监控多个任务),但必须做好同步,否则会出现数据丢失。

方法2

代码

package mainimport ("fmt""time"
)func main() {// 1. 数据通道:传递实际数据dataChan := make(chan interface{}, 3)// 2. 发送完成信号通道:发送方结束后通知sendDone := make(chan struct{})// 3. 接收完成信号通道:接收方结束后通知recvDone := make(chan struct{})// 发送goroutinego func() {for i := 0; i < 10; i++ {time.Sleep(time.Millisecond * 10)dataChan <- ifmt.Printf("发送: %d\n", i)}close(dataChan)       // 发送完毕,关闭数据通道(通知接收方结束)sendDone <- struct{}{} // 发送完成信号}()// 接收goroutinego func() {for item := range dataChan { // 当dataChan关闭且数据取完后,循环自动退出time.Sleep(time.Millisecond * 20)fmt.Printf("接收: %v\n", item)}recvDone <- struct{}{} // 接收完成信号}()// 主程序等待:先等发送完成,再等接收完成<-sendDone  // 阻塞等待发送完成<-recvDone  // 阻塞等待接收完成fmt.Println("所有操作完成")
}

运行结果

标准输出:发送: 0
发送: 1
接收: 0
发送: 2
发送: 3
接收: 1
发送: 4
发送: 5
接收: 2
发送: 6
接收: 3
发送: 7
接收: 4
发送: 8
接收: 5
发送: 9
接收: 6
接收: 7
接收: 8
接收: 9
所有操作完成

那种更好呢

一、效率对比

sync.WaitGroup 略占优势

  1. sync.WaitGroup 是 Go 标准库专门为 “等待一组 goroutine 完成” 设计的同步原语,底层通过原子操作(计数器加减)实现,几乎没有额外开销,执行效率极高。
  2. 它的逻辑简单:Add 增加计数、Done 减少计数、Wait 阻塞直到计数归零,整个过程不涉及复杂的 runtime 调度交互。
    多通道同步的开销稍高
  3. 通道同步依赖于 channel 的发送 / 接收操作,这些操作需要与 Go runtime 的调度器交互(如检查通道状态、唤醒阻塞的 goroutine 等),理论上比原子操作多一些微小的开销。
  4. 额外的信号通道(如 sendDone、recvDone)会占用少量内存(每个通道需要维护内部数据结构),但在实际应用中影响可忽略。

二、实用性与适用场景

sync.WaitGroup 更适合大多数场景

  1. 代码简洁:对于 “等待多个 goroutine 完成” 的场景,WaitGroup 的语义更直观(Add/Done/Wait 直接对应 “注册 - 完成 - 等待” 逻辑),可读性更高。
  2. 扩展性好:如果需要等待多个发送者或接收者(如 10 个发送 goroutine),WaitGroup 只需一次 Add(10) 即可,无需额外定义多个信号通道。
  3. 通用性强:是 Go 社区的 “标准做法”,团队协作时更容易被理解。
    多通道同步适合特定场景
  4. 符合 Go 哲学:更贴合 “用通信实现共享内存” 的 Go 设计思想,通过 channel 传递信号比直接操作计数器更 “Go 式”。
  5. 灵活扩展:如果需要更复杂的同步逻辑(如 “先等待 A 完成,再启动 B,最后等待 B 完成”),通道的阻塞特性可以天然实现流程控制,而 WaitGroup 可能需要配合额外逻辑。
  6. 无依赖:不依赖 sync 包,纯靠语言原生特性实现,适合理解 channel 机制的场景。

三、总结建议

优先选 sync.WaitGroup:在大多数业务代码中,它更简洁、高效、易维护,是同步 goroutine 的 “标准答案”。
选多通道同步:当你需要强调 “通信优先” 的设计,或同步逻辑较复杂(需要通过通道传递更多状态)时,它是更优雅的选择。

本质区别:

WaitGroup 是 “共享状态” 式同步(通过计数器),多通道是 “通信” 式同步(通过信号传递)。两者效率差异微小,选择时主要看代码可读性和场景适配性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91997.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91997.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91997.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web前端文件上传安全与敏感数据安全处理

一、文件上传安全1. 文件上传时的核心安全检查点文件上传是 Web 应用的高风险功能&#xff0c;需从多维度验证&#xff0c;防止恶意文件上传&#xff08;如木马、病毒&#xff09;或路径攻击&#xff0c;关键检查点包括&#xff1a;MIME 类型验证检查请求头中的 Content-Type&a…

文法中的间接左递归

&#x1f31f; 第一步&#xff1a;理解基本概念✅ 什么是文法&#xff08;Grammar&#xff09;&#xff1f;在编程语言或语法分析中&#xff0c;文法 是一组规则&#xff0c;用来描述一种语言的结构。例如&#xff1a;S → A a A → B b B → S c 这表示&#xff1a;S 可以…

Anthropic:跨越生产效能拐点的AI增长飞轮

资本竞赛中的战略转折点 人工智能领域的竞争已经从理念之争演变为资本、算力与地缘政治影响力的全面较量。Anthropic传闻中的1700亿美元估值&#xff0c;如果成为现实&#xff0c;将标志着前沿AI发展格局的地震式转变。这不仅仅是构建更智能模型的问题&#xff0c;更是为主导下…

【Unity3D实例-功能-移动】小兵移动-通过鼠标点击进行

在Unity的世界里&#xff0c;当你轻点鼠标&#xff0c;角色仿佛被赋予了新的使命&#xff0c;沿着一条无形的轨迹&#xff0c;向着地图上的目标点进发。每一次移动&#xff0c;不仅是简单的位移&#xff0c;更是对未知的探索。这种交互&#xff0c;让玩家与游戏世界紧密相连&am…

从0到1学PHP(十四):PHP 性能优化:打造高效应用

目录一、PHP 性能评估与分析1.1 性能指标体系1.2 性能分析工具使用1.3 性能瓶颈定位方法与流程二、代码层面优化技巧2.1 高效的循环与条件判断写法2.2 函数与类的优化设计2.3 内存管理与垃圾回收机制优化三、缓存策略与实现3.1 数据缓存3.2 页面缓存与部分缓存技术3.3 OPcache …

移动管家手机控车系统硬件安装与软件绑定设置

移动管家手机控车系统硬件安装与软件绑定配合使用&#xff0c;具体设置步骤如下&#xff1a;一、硬件安装准备 ‌加装智能控制主机‌&#xff1a;需在车辆上加装移动管家专用智能控制模块&#xff0c;该模块需与原车电路系统连接&#xff0c;并将原车钥匙芯片焊接至主控盒内以实…

51单片机入门:数码管原理介绍及C代码实现

本文是江协科技up的课堂笔记&#xff01;大家可以去bilibili配合这位up的51单片机入门教程食用&#xff0c;效果更佳~我这里进行详细介绍&#xff0c;希望你忘记数码管的时候来这里看看&#xff01;&#xff08;你猜我为什么写这个TAT&#xff09;一.基本介绍LED数码管&#xf…

Apache Camel 简介

相关文档地址 https://camel.apache.org/components/next/index.htmlhttps://camel.apache.org/components/4.10.x/languages/simple-language.htmlhttps://camel.apache.org/manual/exception-clause.htmlhttps://camel.apache.org/manual/index.htmlhttps://camel.apache.org…

IP离线库 输入IP地址立即返回IP所在地址信息(支持Java、Python)

描述 本文实现&#xff1a; 1、离线查询IP地址 2、IP地址精确到区域 3、IP地址支持国外IP 此时需要一个创建&#xff0c;比如我输入一个8.8.8.8的IP立马就需要返回给我一个中文地址信息&#xff0c; 类似于百度的IP搜索&#xff1a; 113.111.186.123如果现在离线环境或者在…

解决MySQL删除/var/lib/mysql下的所有文件后无法启动的问题

删除 MySQL 数据目录 /var/lib/mysql 下的所有文件后&#xff0c;MySQL 将无法启动&#xff0c;因为该目录包含了数据库的所有数据文件、配置文件和系统表。当这些文件被删除时&#xff0c;MySQL 无法找到必要的数据和配置&#xff0c;从而无法正常启动。本文将详细介绍解决这个…

苍穹外卖项目学习——day1(项目概述、环境搭建)

文章目录一、软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境分类二、苍穹外卖项目介绍2.1 定位2.2 功能架构2.3 技术选型三、开发环境搭建3.1 前端环境3.2 后端环境3.3 前后端联调3.4 登录功能优化四、接口文档管理4.1 YApi4.2 Swagger (Knife4j)一、软件开发整体介…

【QT】Qt信号与槽机制详解信号和槽的本质自定义信号和槽带参数的信号和槽

文章目录前言一、信号的本质二、槽的本质三、 信号和槽的使⽤3.1 连接信号和槽四、使用步骤4.1 通过QtCreator⽣成信号槽代码五、 ⾃定义信号和槽5.1 ⽰例1&#xff1a;信号和槽函数初步使用5.2 ⽰例2 两个类使用5.3 示例3 按钮使用触发信号六、 带参数的信号和槽6.1 ⽰例1&…

【OD机试题解法笔记】文件缓存系统

题目描述 请设计一个文件缓存系统&#xff0c;该文件缓存系统可以指定缓存的最大值&#xff08;单位为字节&#xff09;。 文件缓存系统有两种操作&#xff1a; 存储文件&#xff08;put&#xff09;读取文件&#xff08;get&#xff09; 操作命令为&#xff1a; put fileName …

Python中的sys.path与PYTHONPATH全解析:模块导入路径的底层机制与最佳实践

在Python项目开发中&#xff0c;很多人遇到过类似“模块导入失败”、“路径找不到”、“相对导入与绝对导入混乱”等问题。而这些问题的根源&#xff0c;几乎都绕不开一个核心概念——Python模块搜索路径。 今天&#xff0c;我们围绕sys.path 和 PYTHONPATH环境变量&#xff0…

python:如何调节机器学习算法的鲁棒性,以支持向量机SVM为例,让伙伴们看的更明白

鲁棒性&#xff08;Robustness&#xff09;指模型在噪声数据或异常值干扰下保持性能稳定的能力。想详细了解的可参考本人之前的博文 python机器学习&#xff1a;评价智能学习算法性能与效果的常见术语&#xff1a;不收敛、过拟合、欠拟合、泛化能力、鲁棒性一句话、一张图给您…

号源加锁升级思路(解决高并发问题)

原先逻辑链接&#xff1a;号源预约加锁思路_java 预约 接口加锁-CSDN博客 一、进行治疗项目和号源数据缓存 1.新建一个定时任务&#xff0c;主要在凌晨时缓存治疗项目和号源数据 1.1.类中使用redission获取锁&#xff08;用于分布式系统获取数据&#xff0c;保证原子性&…

MCP革命:AI世界的“USB-C”接口如何重塑智能体与外部工具的连接

> 一条标准化的数据通道,让AI从“对话专家”蜕变为“行动专家”,背后是一场由协议驱动的工具连接革命。 2024年11月,Anthropic公司开源了**Model Context Protocol(MCP)**。在短短9个月内,这项技术彻底改变了AI与外部世界的交互方式。截至2025年8月,MCP服务数量**从…

启用“安全登录”组合键(Ctrl+Alt+Delete)解锁

文章目录背景目标功能操作步骤效果背景 在日常工作中&#xff0c;我们有时需要让电脑长期开机运行&#xff08;如处理长任务、作为服务器等&#xff09;。然而&#xff0c;这其中存在一个潜在风险&#xff1a;当电脑处于锁屏或登录界面时&#xff0c;如果有人无意中触碰键盘比…

【08】C++实战篇——C++ 生成动态库.dll 及 C++调用DLL,及实际项目中的使用技巧

文章目录一、创建动态库dll (方法一)1 生成C 动态库dll1.1 创建项目MyDLL1.2 编写.h 和 .cpp文件1.3 设置 及 生成 DLL2 调用 C 动态库dll2.1 创建C 空项目DLLtest2.2 动态库配置 及代码调用测试3 实际项目中的使用技巧3.1 设置dll输出路径3.2 设置头文件引入路径3.3 改进后 测…

kettle插件-kettle http client plus插件,轻松解决https接口无法调用文件流下载问题

场景&#xff1a;小伙伴在使用kettle调用https接口过程中无法正常调用&#xff0c;程序出错问题&#xff0c;今天演示下用自研插件轻松解决这个问题。1、使用openssl 生成自签名证书openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 3652、使用…