【Go】goroutine并发常见的变量覆盖案例


越过山丘
遇见六十岁的我
拄着一根白手杖
在听鸟儿歌唱
我问他幸福与否
他笑着摆了摆手
在他身边围绕着一群
当年流放归来的朋友
他说你不必挽留
爱是一个人的等候
等到房顶开出了花
这里就是天下
总有人幸福白头
总有人哭着分手
无论相遇还是不相遇
都是献给岁月的序曲
                     🎵 杨宗纬《越过山丘》


在 Go 语言中,一个常见的变量覆盖案例涉及到闭包和并发。当你在一个循环中启动多个并发的 goroutine,并且这些 goroutine 引用了循环的迭代变量时,就有可能发生覆盖。这是因为闭包中的变量是通过引用捕获的,而不是通过值。如果闭包在下一次迭代之前没有执行,那么它使用的变量值可能就是迭代变量的最新值。
下面是一个简单的示例,说明了如何在 Go 语言中发生这种覆盖:

package mainimport ("fmt""sync""time"
)func main() {var wg sync.WaitGroupfor i := 0; i < 5; i++ {wg.Add(1)go func() {fmt.Println(i) // 此处的 i 可能在 goroutine 执行时被覆盖wg.Done()}()}// 给 goroutines 时间启动time.Sleep(time.Second)wg.Wait()
}

在上面的代码中,我们启动了 5 个 goroutine,每个都打印变量 i 的值。但是,因为这些 goroutine 可能在 for 循环结束后才开始执行,所以它们都可能打印出同一个数字(通常是最后一个迭代的数字,即 4),而不是每个 goroutine 打印出其对应迭代的数字。

在 Go 中,goroutine 是并发执行的,这意味着它们是在程序的其他部分独立运行的轻量级线程。当你在 for 循环中使用 go 关键字启动一个 goroutine 时,Go 会计划在未来的某个时间点运行这个 goroutine。这个确切的时间点是由 Go 运行时的调度器决定的,它处理所有的并发任务并决定它们的执行顺序。

由于 goroutine 的启动是非阻塞的,for 循环并不会等待每个 goroutine 启动或完成。循环会立即继续执行,进入下一次迭代,最终在所有 goroutine 都被计划后很快完成。

因此,如果 goroutine 内部使用了循环变量,例如上面例子中的 i,并且 goroutine 的执行被推迟到循环完成之后,所有的 goroutine 可能会看到 i 的最终值,因为它们都引用了同一个变量 i。

在实践中,这意味着在循环完成之前,goroutine 可能没有机会开始执行。特别是在循环迅速执行并且没有显式的同步机制(如 sync.WaitGroup)来等待每个 goroutine 的完成的情况下,很可能所有 goroutine 都将在循环结束后才开始执行。

在处理 goroutine 和循环变量时,最佳实践是将每次迭代的变量值传递给 goroutine,以避免意外捕获循环变量的最终值。这可以通过将迭代变量作为参数传递给 goroutine 的匿名函数来实现,从而为每个 goroutine 创建一个变量的副本。这样,即使 goroutine 在循环结束后开始执行,它也将具有正确的迭代值。

为了避免这个问题,你可以在每次迭代中创建一个循环作用域内的变量副本,并将其传递给闭包:

package mainimport ("fmt""sync""time"
)func main() {var wg sync.WaitGroupfor i := 0; i < 5; i++ {wg.Add(1)go func(localI int) { // 使用局部变量 localIfmt.Println(localI) // 打印局部变量,而不是循环变量 iwg.Done()}(i) // 传递当前迭代的 i 的值}// 给 goroutines 时间启动time.Sleep(time.Second)wg.Wait()
}

这个修改后的版本为每个迭代创建了一个 localI 变量的副本,并将其传递给每个 goroutine。这样,每个 goroutine 有它自己的 localI 副本,而且不会被其他迭代覆盖。

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

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

相关文章

Github 2024-03-30 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-30统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目5TypeScript项目2C项目1Jupyter Notebook项目1Go项目1非开发语言项目1Mojo项目1开源 iOS 应用合作列表 创建周期:3351 天协议类型:…

ubuntu18.04安装qt

ubuntu18.04安装qt 1、下载文件 比如我下载的是5.13.0版本 下载链接 2、安装 wget https://download.qt.io/archive/qt/5.13/5.13.0/qt-opensource-linux-x64-5.13.0.runsudo chmod x qt-opensource-linux-x64-5.13.0.runsudo ./qt-opensource-linux-x64-5.13.0.run参考文…

数学分析复习:等价量的概念

本篇文章适合个人复习翻阅&#xff0c;不建议新手入门使用 等价量 定义&#xff1a;无穷小量、无穷大量 若 lim ⁡ x → x 0 f ( x ) 0 \lim\limits_{x\to x_0}f(x)0 x→x0​lim​f(x)0&#xff0c;则称当 x → x 0 x\to x_0 x→x0​ 时&#xff0c; f ( x ) f(x) f(x) 是无…

开源知识库平台Raneto--使用Docker部署Raneto

文章目录 一、Raneto介绍1.1 Raneto简介1.2 知识库介绍 二、阿里云环境2.1 环境规划2.2 部署介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Raneto镜像五、部署Raneto知识库平台5.1 创建挂载目录5.2 编辑config.js文件5.…

MySQL InnoDB 之 多版本并发控制(MVCC)

多版本并发控制&#xff08;MVCC&#xff0c;Multi-Version Concurrency Control&#xff09;是数据库管理系统中用于提供高并发性和在事务处理中实现隔离级别的一种技术。MVCC 允许系统在不完全锁定数据库资源的情况下&#xff0c;处理多个并发事务&#xff0c;从而提高了数据…

Datacom HCIP笔记-OSPF协议 之二

链路&#xff1a;路由器之间的相连的链路 状态&#xff1a;链路上的参数在某一时刻的状态 单边邻居 one way&#xff1f; 收到对端发来的hello报文&#xff0c;其中没有自己的router id LSA类型&#xff1a; 1类LSA&#xff1a;描述路由器自身加入到ospf进程中的直连链路的状态…

大数据-TXT文本重复行计数工具

支持系统类型&#xff1a;Windows 64位系统 Linux 64位系统 苹果64位系统 硬盘要求&#xff1a;固态硬盘&#xff08;有效剩余磁盘空间大小最低3倍于大数据文件的大小&#xff09; 内存要求&#xff1a;最低8G&#xff08;例如只有几百G数据&#xff09; 如果处理TB级大数据文…

STM32 软件I2C方式读取AS5600磁编码器获取角度例程

STM32 软件I2C方式读取AS5600磁编码器获取角度例程 &#x1f516;本例程使用正点原子例程作为工程模板创建。 &#x1f4d8; 硬件电路部分 &#x1f33f;原理图部分&#xff1a; &#x1f33f;PCB布线和电路 ✨注意事项&#xff1a;有些硬件需要I2C上拉&#xff0c;否则检…

校园局域网钓鱼实例

Hello &#xff01; 我是"我是小恒不会java" 本文仅作为针对普通同学眼中的网络安全&#xff0c;设计的钓鱼案例也是怎么简陋怎么来 注&#xff1a;本文不会外传代码&#xff0c;后端已停止使用&#xff0c;仅作为学习使用 基本原理 内网主机扫描DNS劫持前端模拟后端…

HTTP和tcp的区别

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;和TCP&#xff08;Transmission Control Protocol&#xff09;是互联网通信中的两个不同层次的协议&#xff0c;它们之间有着以下区别&#xff1a; 层次不同&#xff1a; TCP是传输层协议&#xff0c;负责在网络上可靠…

【2023】kafka入门学习与使用(kafka-2)

目录&#x1f4bb; 一、基本介绍1、产生背景2、 消息队列介绍2.1、消息队列的本质作用2.2、消息队列的使用场景2.3、消息队列的两种模式2.4、消息队列选型&#xff1a; 二、kafka组件1、核心组件概念2、架构3、基本使用3.1、消费消息3.2、单播和多播消息的实现 4、主题和分区4.…

大模型与数据分析:探索Text-to-SQL

当今大模型如此火热&#xff0c;作为一名数据同学&#xff0c;持续在关注LLM是如何应用在数据分析中的&#xff0c;也关注到很多公司推出了AI数智助手的产品&#xff0c;比如火山引擎数智平台VeDI—AI助手、 Kyligence Copilot AI数智助理、ThoughtSpot等&#xff0c;通过接入人…

Node.js的Event Loop:六个阶段详解

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

括号生成(回溯+剪枝)

22. 括号生成 - 力扣&#xff08;LeetCode&#xff09; 题目描述 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 样例输入 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["((()))&q…

五年前端的面试之旅

哈喽我是树酱&#xff0c;最近整理了下前端面试相关的知识题库&#xff0c;借此分享给各位小伙伴&#xff0c;帮助小伙伴早日拿到钟意的offer&#xff01; 前言 最近就业市场不景气&#xff0c;跟大环境较差也有关&#xff0c;确实给我们也会带来一定的挑战。在招聘网站投简历的…

数据仓库的发展历程

数据仓库的概念可以追溯到20世纪60年代,但真正形成理论并被企业广泛应用还需要一个较长的发展过程。大致可以分为以下几个阶段: 决策支持系统(DSS)时期(1960s-1970s) 这一时期,随着管理信息系统(MIS)和电子计算机的兴起,企业开始尝试构建面向决策的数据处理系统。最初的决策支…

python批量转化pdf图片为jpg图片

1.把pdf图片批量转为jpg&#xff1b;需要注意的是&#xff0c;需要先安装poppler这个软件&#xff0c;具体安装教程放在下面代码中了 2.代码 #poppler安装教程参考&#xff1a;https://blog.csdn.net/wy01415/article/details/110257130 #windows上poppler下载链接&#xff1a…

从零开始机器学习(机器学习 监督学习之线性回归 损失函数及可视化 梯度下降 线性回归的平方误差损失函数 lab实验)

文章目录 机器学习定义监督学习之线性回归损失函数及可视化梯度下降线性回归的平方误差损失函数lab实验 机器学习定义 机器学习就是机器通过不断训练数据集从逐渐知道正确的结果 机器学习包括监督学习和非监督学习 监督学习&#xff1a;需要输入数据和结果数据来不断训练学习…

Java-常见面试题收集(八)

十五 JDBC 1 JDBC 访问数据库的基本步骤 加载驱动&#xff0c;通过 DriverManager 对象获取连接对象 Connection&#xff0c;通过连接对象获取会话&#xff0c;通过会话进行数据的增删改查封装对象&#xff0c;关闭资源 2 PreparedStatement 和 Statement 的区别 PreparedSta…

linux0.11中jmpi 0,8解析

系统在执行该行代码时已经为保护模式, jmpi 0,8会将段选择子(selector)载入cs段寄存器&#xff0c;并计算出逻辑地址。 段选择子的结构如下&#xff1a; 段选择子包括三部分&#xff1a;描述符索引&#xff08;index&#xff09;、TI、请求特权级&#xff08;RPL&#xff09;。…