Go语言的数据竞争 (Data Race) 和 竞态条件 (Race Condition)

文章精选推荐

1 JetBrains Ai assistant 编程工具让你的工作效率翻倍
2 Extra Icons:JetBrains IDE的图标增强神器
3 IDEA插件推荐-SequenceDiagram,自动生成时序图
4 BashSupport Pro 这个ides插件主要是用来干嘛的 ?
5 IDEA必装的插件:Spring Boot Helper的使用与功能特点
6 Ai assistant ,又是一个写代码神器
7 Cursor 设备ID修改器,你的Cursor又可以继续试用了

文章正文

在并发编程中,数据竞争 (Data Race)竞态条件 (Race Condition) 是两个常见的问题,尤其在 Go 语言的 Goroutine 中使用共享数据时,更容易出现这些问题。它们的含义和根源有所不同,但都可能导致程序的不可预测行为。

1. 数据竞争 (Data Race)

定义

数据竞争是指两个或多个 Goroutine 同时访问同一个共享变量,并且至少有一个操作是写操作,且没有进行适当的同步

在这种情况下,程序的行为是未定义的,因为 Goroutine 的执行顺序可能不一致,导致共享变量的值难以预测。

示例代码

package mainimport ("fmt""time"
)func main() {var counter intfor i := 0; i < 10; i++ {go func() {counter++}()}time.Sleep(1 * time.Second)fmt.Println("Final Counter:", counter)
}
运行结果:
  • 每次运行,counter 的值可能不同,比如有时是 7,有时是 10,甚至更小。
  • 原因:多个 Goroutine 同时读写 counter,但没有任何同步措施,造成数据竞争。
修复方法

使用互斥锁(sync.Mutex)或其他同步机制。

package mainimport ("fmt""sync""time"
)func main() {var (counter intmu      sync.Mutex)for i := 0; i < 10; i++ {go func() {mu.Lock()counter++mu.Unlock()}()}time.Sleep(1 * time.Second)fmt.Println("Final Counter:", counter)
}

2. 竞态条件 (Race Condition)

定义

竞态条件是一种更广泛的问题,指程序的行为依赖于 Goroutine 的执行顺序,如果执行顺序发生改变,程序的逻辑可能出错。

竞态条件和数据竞争的区别

  • 数据竞争是竞态条件的一种表现形式。
  • 竞态条件可能存在于更高层次的逻辑上,即使没有共享数据,也可能由于执行顺序的不确定性导致错误。

示例代码

package mainimport ("fmt""sync"
)var balance intfunc Deposit(amount int, wg *sync.WaitGroup) {defer wg.Done()currentBalance := balancecurrentBalance += amountbalance = currentBalance
}func main() {var wg sync.WaitGroupbalance = 1000wg.Add(2)go Deposit(500, &wg) // Goroutine 1go Deposit(300, &wg) // Goroutine 2wg.Wait()fmt.Println("Final Balance:", balance)
}
运行结果:
  • 理想情况下,Final Balance 应该是 1000 + 500 + 300 = 1800
  • 实际运行可能得到错误结果,比如 15001300
  • 原因:两个 Goroutine 在读 balance 和写 balance 之间没有同步机制,导致执行顺序不同。
修复方法

使用互斥锁或原子操作确保更新是原子的。

package mainimport ("fmt""sync"
)var balance int
var mu sync.Mutexfunc Deposit(amount int, wg *sync.WaitGroup) {defer wg.Done()mu.Lock()defer mu.Unlock()balance += amount
}func main() {var wg sync.WaitGroupbalance = 1000wg.Add(2)go Deposit(500, &wg)go Deposit(300, &wg)wg.Wait()fmt.Println("Final Balance:", balance) // Correct result: 1800
}

3. 两者的区别

特点数据竞争 (Data Race)竞态条件 (Race Condition)
范围专注于并发时的共享变量访问问题更广泛,涵盖所有因执行顺序导致的问题
表现形式未同步的共享数据读写不正确的执行顺序导致逻辑错误
影响导致不可预测的值,程序行为未定义程序可能出错,结果不符合预期
是否需要同步机制必须对共享数据加锁或同步通常通过逻辑设计避免执行顺序依赖
诊断工具go run -race 可检测通常需要通过代码审查或测试发现

4. Go 语言的检测工具

Go 提供了内置的 -race 检测工具,可以帮助开发者快速发现数据竞争问题。

使用方法

go run -race main.go
示例输出

对于存在数据竞争的代码,-race 工具会输出类似以下的日志:

WARNING: DATA RACE
Read at 0x00c0000a4010 by goroutine 7:main.main.func1()/path/to/main.go:10 +0x45Previous write at 0x00c0000a4010 by goroutine 6:main.main.func1()/path/to/main.go:10 +0x45

注意

  • -race 工具的检测范围仅限于数据竞争,不能直接发现更高层次的竞态条件。
  • 使用 -race 会增加程序的运行时间和内存开销,但非常适合调试。

5. 最佳实践

为了避免数据竞争和竞态条件,在 Go 的并发编程中可以采用以下策略:

  1. 尽量避免共享数据

    • 使用 Goroutine 和 channel 传递数据,避免直接共享变量。
    • Go 提倡通过通信共享数据,而不是通过共享数据通信。
  2. 使用同步原语

    • 使用 sync.Mutexsync.RWMutex 保护共享数据。
    • 使用 sync.WaitGroup 等同步工具来确保 Goroutine 正确完成。
  3. 优先选择原子操作

    • 对于简单的计数器或布尔值更新,使用 sync/atomic 提供的原子操作。
  4. 使用检测工具

    • 在开发和测试阶段,始终运行带有 -race 的程序,检测数据竞争问题。
  5. 逻辑设计避免竞态

    • 设计程序时,尽量减少对执行顺序的依赖。
    • 确保程序逻辑在任何 Goroutine 执行顺序下都能正确运行。

6. 总结

  • 数据竞争 是竞态条件的一种特例,特指未同步的共享变量访问问题,而 竞态条件 则涵盖了所有执行顺序依赖导致的错误。
  • Go 语言通过 Goroutine 和 channel 提供了并发编程的强大能力,但开发者需要小心处理共享数据,避免数据竞争和竞态条件。
  • 利用 sync 包、atomic 包以及 -race 工具,可以有效防止和检测这些问题。

在并发编程中,始终秉持 清晰的同步策略简洁的设计哲学 是关键。

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

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

相关文章

Node.js - Express框架

1. 介绍 Express 是一个基于 Node.js 的 Web 应用程序框架&#xff0c;主要用于快速、简便地构建 Web 应用程序 和 API。它是目前最流行的 Node.js Web 框架之一&#xff0c;具有轻量级、灵活和功能丰富的特点。 核心概念包括路由&#xff0c;中间件&#xff0c;请求与响应&a…

《光学遥感图像中显著目标检测的多内容互补网络》2021-9

一、简介 在本文中&#xff0c;我们提出了一种新的多内容互补网络 &#xff08;MCCNet&#xff09; 来探索 RSI-SOD 的多内容互补性。具体来说&#xff0c;MCCNet 基于通用的编码器-解码器架构&#xff0c;并包含一个名为 multi-content complementation module &#xff08;MC…

【STM8S】STM8S之自定义短、长、连击按键

本文最后修改时间&#xff1a;2018年10月22日 01:57 一、本节简介 本文介绍STM8S系列如何实现按键的短按、长按、连击。 二、实验平台 编译软件&#xff1a;IAR for STM8 1.42.2 硬件平台&#xff1a;stm8s003f3p6开发板 仿真器&#xff1a;ST-LINK 库函数版本&#xff1a…

数据库(MySQL)练习

数据库&#xff08;MySQL&#xff09;练习 一、练习1.15练习练习 二、注意事项2.1 第四天 一、练习 1.15练习 win11安装配置MySQL超详细教程: https://baijiahao.baidu.com/s?id1786910666566008458&wfrspider&forpc 准备工作&#xff1a; mysql -uroot -p #以管理…

【深度学习地学应用|滑坡制图、变化检测、多目标域适应、感知学习、深度学习】跨域大尺度遥感影像滑坡制图方法:基于原型引导的领域感知渐进表示学习(一)

【深度学习地学应用|滑坡制图、变化检测、多目标域适应、感知学习、深度学习】跨域大尺度遥感影像滑坡制图方法&#xff1a;基于原型引导的领域感知渐进表示学习&#xff08;一&#xff09; 【深度学习地学应用|滑坡制图、变化检测、多目标域适应、感知学习、深度学习】跨域大…

《C++11》并发库:简介与应用

在C11之前&#xff0c;C并没有提供原生的并发支持。开发者通常需要依赖于操作系统的API&#xff08;如Windows的CreateThread或POSIX的pthread_create&#xff09;或者第三方库&#xff08;如Boost.Thread&#xff09;来创建和管理线程。这些方式存在以下几个问题&#xff1a; …

了解Node.js

Node.js是一个基于V8引擎的JavaScript运行时环境&#xff0c;它允许JavaScript代码在服务器端运行&#xff0c;从而实现后端开发。Node.js的出现&#xff0c;使得前端开发人员可以利用他们已经掌握的JavaScript技能&#xff0c;扩展技能树并成为全栈开发人员。本文将深入浅出地…

js解决 Number失精度问题

const updatePromises adinfo.rows.map(async item > {const cwf await uniCloud.httpclient.request("https://api.oceanengine.com/open_api/v3.0/project/list/", {method: GET,data: {advertiser_id: item.account_id},// 1. 指定text数据格式dataType: tex…

实力认证 | 海云安入选《信创安全产品及服务购买决策参考》

近日&#xff0c;国内知名安全调研机构GoUpSec发布了2024年中国网络安全行业《信创安全产品及服务购买决策参考》&#xff0c;报告从产品特点、产品优势、成功案例、安全策略等维度对各厂商信创安全产品及服务进行调研了解。 海云安凭借AI大模型技术在信创安全领域中的创新应用…

windows系统“GameInputRedist.dll”文件丢失或错误导致游戏运行异常如何解决?windows系统DLL文件修复方法

GameInputRedist.dll是存放在windows系统中的一个重要dll文件&#xff0c;缺少它可能会造成部分游戏不能正常运行。当你的电脑弹出提示“无法找到GameInputRedist.dll”或“计算机缺少GameInputRedist.dll”等错误问题&#xff0c;请不用担心&#xff0c;我们将深入解析DLL文件…

概率论考前一天

判断是不是分布函数&#xff1a;单调不减&#xff0c;右连续&#xff0c;F负无穷为0&#xff0c; F正无穷为1 判断是不是密度函数&#xff1a;非负性&#xff08;函数任意地方都大于0&#xff09;&#xff0c;规范&#xff1a;积分为1

FPGA工程师成长四阶段

朋友&#xff0c;你有入行三年、五年、十年的职业规划吗&#xff1f;你知道你所做的岗位未来该如何成长吗&#xff1f; FPGA行业的发展近几年是蓬勃发展&#xff0c;有越来越多的人才想要或已经踏进了FPGA行业的大门。很多同学在入行FPGA之前&#xff0c;都会抱着满腹对职业发…

springCloudGateway+nacos自定义负载均衡-通过IP隔离开发环境

先说一下想法&#xff0c;小公司开发项目&#xff0c;参考若依框架使用的spring-cloud-starter-gateway和spring-cloud-starter-alibaba-nacos, 用到了nacos的配置中心和注册中心&#xff0c;有多个模块&#xff08;每个模块都是一个服务&#xff09;。 想本地开发&#xff0c;…

向量数据库如何助力Text2SQL处理高基数类别数据

01. 导语 Agent工作流和 LLMs &#xff08;大语言模型&#xff09;的出现&#xff0c;让我们能够以自然语言交互的模式执行复杂的SQL查询&#xff0c;并彻底改变Text2SQL系统的运行方式。其典型代表是如何处理High-Cardinality Categorical Data &#xff08;高基数类别数据&am…

qBittorent访问webui时提示unauthorized解决方法

现象描述 QNAP使用Container Station运行容器&#xff0c;使用Docker封装qBittorrent时&#xff0c;访问IP:PORT的方式后无法访问到webui&#xff0c;而是提示unauthorized&#xff0c;如图&#xff1a; 原因分析 此时通常是由于设备IP与qBittorrent的ip地址不在同一个网段导致…

工程水印相机结合图纸,真实现场时间地点,如何使用水印相机,超简单方法只教一次!

在工程管理领域&#xff0c;精准记录现场信息至关重要。水印相机拍照功能&#xff0c;为工程人员提供了强大的现场信息记录工具&#xff0c;助力工程管理和统计工程量&#xff0c;更可以将图片分享到电脑、分享给同事&#xff0c;协同工作。 一、打开图纸 打开手机版CAD快速看图…

GO语言实现KMP算法

前言 本文结合朱战立教授编著的《数据结构—使用c语言&#xff08;第五版&#xff09;》&#xff08;以下简称为《数据结构&#xff08;第五版&#xff09;朱站立》&#xff09;中4.4.2章节内容编写&#xff0c;KMP的相关概念可参考此书4.4.2章节内容。原文中代码是C语言&…

LeetCode 热题 100_从前序与中序遍历序列构造二叉树(47_105_中等_C++)(二叉树;递归)

LeetCode 热题 100_从前序与中序遍历序列构造二叉树&#xff08;47_105&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;递归&#xff09;&#xff1a; 代码实现代码实现&#xff08;思路一&#xff08;递归…

文档智能:OCR+Rocketqa+layoutxlm <Rocketqa>

此次梳理Rocketqa&#xff0c;个人认为该篇文件讲述的是段落搜索的改进点&#xff0c;关于其框架&#xff1a;粗检索 重排序----&#xff08;dual-encoder architecture&#xff09;&#xff0c;讲诉不多&#xff0c;那是另外的文章&#xff1b; 之前根据文档智能功能&#x…

ubuntu官方软件包网站 字体设置

在https://ubuntu.pkgs.org/22.04/ubuntu-universe-amd64/xl2tpd_1.3.16-1_amd64.deb.html搜索找到需要的软件后&#xff0c;点击&#xff0c;下滑&#xff0c; 即可在Links和Download找到相关链接&#xff0c;下载即可&#xff0c; 但是找不到ros的安装包&#xff0c; 字体设…