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.pswp.cn/web/66130.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66130.shtml
英文地址,請注明出處:http://en.pswp.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; 【深度學習地學應用|滑坡制圖、變化檢測、多目標域適應、感知學習、深度學習】跨域大…

RPC實現原理,怎么跟調用本地一樣

回答1 要讓?絡通信細節對使?者透明&#xff0c;我們需要對通信細節進?封裝&#xff0c;我們先看下?個 RPC 調?的流程涉及到哪些通 信細節&#xff1a; 1. 服務消費?&#xff08; client &#xff09;調?以本地調??式調?服務&#xff1b; 2. client stub 接收到調…

《C++11》并發庫:簡介與應用

在C11之前&#xff0c;C并沒有提供原生的并發支持。開發者通常需要依賴于操作系統的API&#xff08;如Windows的CreateThread或POSIX的pthread_create&#xff09;或者第三方庫&#xff08;如Boost.Thread&#xff09;來創建和管理線程。這些方式存在以下幾個問題&#xff1a; …

【記錄52】el-table-column 添加fixed屬性 滾動條無法滑動

問題&#xff1a; el-table-column 添加fixed屬性 滾動條無法滑動 使用element UI組件&#xff0c;用到el-table的el-table-column的fixed屬性時&#xff0c;當滾動條長度小于固定列時&#xff0c;滾動條無法通過鼠標去點擊滑動操作 原因 fixed是用來固定列的屬性&#xff0c;其…

rtthread學習筆記系列-- 22 dataqueue

文章目錄 22 dataqueue https://github.com/wdfk-prog/RT-Thread-Study 22 dataqueue 消息隊列&#xff1a;消息隊列能夠接收來自線程或中斷服務例程中不固定長度的消息&#xff0c;并把消息緩存在自己的內存空間中。其他線程也能夠從消息隊列中讀取相應的消息&#xff0c;而當…

了解Node.js

Node.js是一個基于V8引擎的JavaScript運行時環境&#xff0c;它允許JavaScript代碼在服務器端運行&#xff0c;從而實現后端開發。Node.js的出現&#xff0c;使得前端開發人員可以利用他們已經掌握的JavaScript技能&#xff0c;擴展技能樹并成為全棧開發人員。本文將深入淺出地…

微信小程序在使用頁面棧保存頁面信息時,如何避免數據丟失?

微信小程序在使用頁面棧保存頁面信息時避免數據丟失的方法&#xff1a; 一、使用全局變量存儲關鍵數據&#xff1a; 定義一個全局變量&#xff0c;例如在 app.js 中&#xff0c;用于存儲頁面的重要信息。在頁面的 onHide 或 onUnload 生命周期中&#xff0c;將需要保存的數據…

文件上傳 分片上傳

分片上傳則是將一個大文件分割成多個小塊分別上傳&#xff0c;最后再由服務器合并成完整的文件。這種做法的好處是可以并行處理多個小文件&#xff0c;提高上傳效率&#xff1b;同時&#xff0c;如果某一部分上傳失敗&#xff0c;只需要重傳這一部分&#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大模型技術在信創安全領域中的創新應用…

Picocli 命令行框架

官方文檔 https://picocli.info/ 官方提供的快速入門教程 https://picocli.info/quick-guide.html 使用 Picocli 創建命令行應用程序 Picocli 是一個用于構建 Java 命令行應用的強大框架&#xff0c;它簡化了參數解析和幫助消息生成的過程。 下面是如何使用 Picocli 構建簡單命…

windows系統“GameInputRedist.dll”文件丟失或錯誤導致游戲運行異常如何解決?windows系統DLL文件修復方法

GameInputRedist.dll是存放在windows系統中的一個重要dll文件&#xff0c;缺少它可能會造成部分游戲不能正常運行。當你的電腦彈出提示“無法找到GameInputRedist.dll”或“計算機缺少GameInputRedist.dll”等錯誤問題&#xff0c;請不用擔心&#xff0c;我們將深入解析DLL文件…

M4Pro安裝homebrew并基于homebrew安裝MySQL踩坑記錄

系統偏好設置允許安裝任何來源應用&#xff1a;sudo spctl --master-disable 清除提示已損壞軟件的安全隔離&#xff0c;重新安裝&#xff1a; xattr -cr 空格&#xff0b;App路徑 安裝homebrew&#xff1a; /opt/homebrew/Cellar 安裝包目錄 /opt/homebrew/etc 默認運行目…

tmux 中鼠標滾動異常:^[[A和^[[B是什么以及如何解決

tmux 中鼠標滾動異常問題及解決方案 在使用 tmux 時&#xff0c;有時我們會遇到一個現象&#xff1a;當嘗試使用鼠標滾輪滾動窗口內容時&#xff0c;終端中會出現一串類似 ^[[A^[[A 的字符。這讓人困惑&#xff0c;不知道鼠標滾動為什么不起作用&#xff0c;也不清楚這些字符究…

【Vue】mouted、created、computed區別

mouted、created、computed區別 前端vue重構 — computed、watch、組件通信等常用知識整理 created和mouted都是vue生命周期中的鉤子函數&#xff0c;通常用來做一些初始化的工作&#xff0c;比如發送http請求、對組件綁定自定義事件 created&#xff1a;實例創建完后立即調用…

前端如何設計一個回溯用戶操作的方案

同一個項目&#xff0c;為什么我本地無法復現&#xff0c;只有客戶的設備才復現&#xff1f; 如何獲取用戶的操作路徑呢&#xff1f; 兩種方案&#xff1a;埋點和rrweb 埋點就很簡單了&#xff0c;將所有可能操作的節點都進行預埋數據&#xff1b;但埋點簡單并不省心&#xff…