Go語言并發編程 ------ 鎖機制詳解

Go語言提供了豐富的同步原語來處理并發編程中的共享資源訪問問題。其中最基礎也最常用的就是互斥鎖(Mutex)和讀寫鎖(RWMutex)。

1. sync.Mutex(互斥鎖)

Mutex核心特性

  • 互斥性/排他性同一時刻只有一個goroutine能持有鎖
  • 不可重入:同一個goroutine重復加鎖會導致死鎖
  • 零值可用sync.Mutex的零值就是未鎖定的互斥鎖
  • 非公平鎖:不保證goroutine獲取鎖的順序

Mutex例子

例1:

package mainimport ("fmt""math/rand""sync""time"
)var wait sync.WaitGroup
var count = 0var lock sync.Mutexfunc main() {wait.Add(10)for i := 0; i < 10; i++ {go func(data *int) {// 加鎖lock.Lock()// 模擬訪問耗時time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))// 訪問數據temp := *data// 模擬計算耗時time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))ans := 1// 修改數據*data = temp + ans// 解鎖lock.Unlock()fmt.Println(*data)wait.Done()}(&count)}wait.Wait()fmt.Println("最終結果", count)
}

輸出:

1
2
3
4
5
6
7
8
9
10
最終結果 10

解讀:

  • lock 是一個互斥鎖,用于確保在任何時刻只有一個 goroutine 可以訪問和修改 count 變量,防止數據競爭。
  • 每個 goroutine 首先通過 lock.Lock() 加鎖,確保在同一時間只有一個 goroutine 可以修改 count。
  • time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))) 模擬了對數據的訪問和計算耗時,這里的隨機數生成器用于在每次循環中生成一個 0 到 999 之間的隨機整數,作為睡眠的時間
  • wait.Wait() 阻塞主 goroutine,直到等待組中的所有 goroutine 都完成任務。
  • fmt.Println("最終結果", count) 打印 count 的最終值。

在 Go 語言中,func(data *int) 這樣的寫法是用來定義一個匿名函數,并且該匿名函數接受一個參數,參數類型是指向整型的指針。在這段代碼的目的是在并發環境中對一個共享變量 count 進行修改,以避免數據競爭。

  • go func(data *int) { ... }(&count) 這里的 go 關鍵字用于啟動一個新的 goroutine。
  • func(data *int) { ... } 是一個匿名函數,它接受一個參數 data,這個參數是一個指向整型的指針。
  • (&count) 表示傳遞給匿名函數的參數是 count 變量的地址。通過傳遞指針,匿名函數可以直接訪問和修改 count 的值。

例2

package mainimport ("fmt""sync""time"
)var (counter intlock    sync.Mutex
)func main() {var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go increment(&wg)}wg.Wait()fmt.Println("Final counter:", counter)
}func increment(wg *sync.WaitGroup) {defer wg.Done()lock.Lock()         // 加鎖defer lock.Unlock() // 使用defer確保解鎖// 臨界區temp := countertime.Sleep(1 * time.Millisecond)counter = temp + 1
}

輸出:

Final counter: 10

解讀:

  • var wg sync.WaitGroup:聲明了一個等待組wg,用于等待所有goroutine完成。
  • wg.Add(1):為每次循環增加一個等待計數。
  • go increment(&wg):啟動goroutine運行increment函數,并傳入等待組的地址。
  • wg.Wait():等待所有等待計數為零,即所有goroutine完成。
  • defer wg.Done():使用defer關鍵字確保函數執行完畢后調用wg.Done(),減少等待組的一個計數。
  • lock.Lock():在函數執行前加鎖,防止多個goroutine同時訪問counter。
  • defer lock.Unlock():同樣使用defer關鍵字確保函數執行完畢后解鎖。
  • 臨界區代碼段:將counter的值賦給temp,休眠1毫秒,然后將counter設置為temp + 1。這里通過休眠模擬了一個耗時操作。

2. sync.RWMutex(讀寫鎖)

Go 中讀寫互斥鎖的實現是?sync.RWMutex,它也同樣實現了?Locker?接口,但它提供了更多可用的方法,如下:

// 加讀鎖
func (rw *RWMutex) RLock()// 非阻塞地嘗試加讀鎖 (Go 1.18+)
func (rw *RWMutex) TryRLock() bool// 解讀鎖
func (rw *RWMutex) RUnlock()// 加寫鎖
func (rw *RWMutex) Lock()// 非阻塞地嘗試加寫鎖 (Go 1.18+)
func (rw *RWMutex) TryLock() bool// 解寫鎖
func (rw *RWMutex) Unlock()

1. RWMutex基本概念

讀寫鎖的特點

  • 并發讀:多個goroutine可以同時持有讀鎖
  • 互斥寫:寫鎖是排他的,同一時間只能有一個goroutine持有寫鎖
  • 寫優先:當有寫鎖等待時,新的讀鎖請求會被阻塞,防止寫鎖饑餓

Mutex的區別

特性MutexRWMutex
并發讀不支持支持多個goroutine同時讀
并發寫不支持不支持
性能一般讀多寫少場景性能更好
復雜度簡單相對復雜

2. RWMutex的工作原理

鎖狀態

  • 當寫鎖被持有時:所有讀鎖和寫鎖請求都會被阻塞
  • 當讀鎖被持有時:新的讀鎖請求可以立即獲得鎖,寫鎖請求會被阻塞
  • 當寫鎖請求等待時:新的讀鎖請求會被阻塞(寫優先)

內部實現要點

  1. 讀者計數:記錄當前持有讀鎖的goroutine數量
  2. 寫者標記:標識是否有goroutine持有或等待寫鎖
  3. 寫者信號量:用于喚醒等待的寫者
  4. 讀者信號量:用于喚醒等待的讀者

3. RWMutex的例子

線程安全的緩存實現

type Cache struct {mu    sync.RWMutexitems map[string]interface{}
}func (c *Cache) Get(key string) (interface{}, bool) {c.mu.RLock()defer c.mu.RUnlock()item, found := c.items[key]return item, found
}func (c *Cache) Set(key string, value interface{}) {c.mu.Lock()defer c.mu.Unlock()c.items[key] = value
}func (c *Cache) Delete(key string) {c.mu.Lock()defer c.mu.Unlock()delete(c.items, key)
}

解讀

Cache 結構體

  • items:一個映射(map),鍵為字符串,值為接口類型(interface{}),用于存儲緩存數據。
  • mu:一個sync.RWMutex實例,用于控制對items的并發訪問。

Get 方法:

  • c.mu.RLock():獲取讀鎖,允許多個讀協程同時訪問items。
  • defer c.mu.RUnlock():確保在函數返回前釋放讀鎖
  • item, found := c.items[key]:從items中獲取指定key對應的值,并判斷該key是否存在。
  • return item, found:返回獲取的值和是否找到的布爾值。

Set 方法:

  • c.mu.Lock():獲取寫鎖,確保只有一個寫協程可以訪問items。
  • defer c.mu.Unlock():確保在函數返回前釋放寫鎖
  • c.items[key] = value:將指定key對應的值設置為value。

Delete 方法:

  • c.mu.Lock():獲取寫鎖,確保只有一個寫協程可以訪問items。
  • defer c.mu.Unlock():確保在函數返回前釋放寫鎖。
  • delete(c.items, key):從items中刪除指定key對應的鍵值對。

3.互斥鎖和讀寫鎖的區別和應用場景

核心區別對比

特性互斥鎖(Mutex)讀寫鎖(RWMutex)
并發讀完全互斥,讀操作也需要獨占鎖允許多個goroutine同時持有讀鎖
并發寫互斥,同一時間只有一個寫操作互斥,同一時間只有一個寫操作
鎖類型單一鎖類型區分讀鎖(RLock)和寫鎖(Lock)
性能開銷較高(所有操作都互斥)讀操作開銷低,寫操作開銷與Mutex相當
實現復雜度簡單相對復雜
適用場景讀寫操作頻率相當或寫多讀少讀操作遠多于寫操作的場景

選擇場景

  1. 優先考慮RWMutex當

    • 讀操作次數是寫操作的5倍以上
    • 讀操作臨界區較大(耗時較長)
    • 需要支持高頻并發讀取
  2. 選擇Mutex當

    • 讀寫操作頻率相當(寫操作占比超過20%)
    • 臨界區非常小(幾個CPU周期就能完成)
    • 代碼簡單性比極致性能更重要
    • 需要鎖升級/降級(雖然Go不支持,但Mutex更不容易出錯)
  3. 特殊考慮

    • 對于極高性能場景,可考慮atomic原子操作
    • 對于復雜場景,可考慮sync.Map或分片鎖

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93654.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93654.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93654.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

8月17日星期天今日早報簡報微語報早讀

8月17日星期天&#xff0c;農歷閏六月廿四&#xff0c;早報#微語早讀。1、《南京照相館》領跑&#xff0c;2025年暑期檔電影總票房破95億&#xff1b;2、神舟二十號圓滿完成第三次出艙任務&#xff1b;3、宇樹G1人形機器人100米障礙賽再奪金牌&#xff1b;4、廣東佛山新增報告基…

在QML中使用Chart組件

目錄前言1. 如何安裝 Chart 組件2. 創建 QML 工程時的常見問題3. 解決方案&#xff1a;改用 QApplication QQuickView修改主函數&#xff08;main.cpp&#xff09;4. QApplication 與 QGuiApplication 的差異為什么 Qt Charts 需要 QApplication&#xff1f;總結示例下載前言 …

【P40 6-3】OpenCV Python——圖像融合(兩張相同屬性的圖片按比例疊加),addWeighted()

P40 6-3 文章目錄import cv2 import numpy as npback cv2.imread(./back.jpeg) smallcat cv2.imread(./smallcat1.jpeg)#只有兩張圖的屬性是一樣的才可以進行溶合 print(back.shape) print(smallcat.shape)result cv2.addWeighted(smallcat, 0.7, back, 0.3, 0) cv2.imshow(…

傳輸層協議 TCP(1)

傳輸層協議 TCP&#xff08;1&#xff09; TCP 協議 TCP 全稱為 “傳輸控制協議(Transmission Control Protocol”). 人如其名, 要對數據的傳輸進行一個詳細的控制; TCP 協議段格式 ? 源/目的端口號: 表示數據是從哪個進程來, 到哪個進程去; ? 32 位序號/32 位確認號: 后面詳…

黎陽之光:以動態感知與 AI 深度賦能,引領電力智慧化轉型新革命

當全球能源結構加速向清潔低碳轉型&#xff0c;新型電力系統建設成為國家戰略核心&#xff0c;電力行業正經歷從傳統運維向智慧化管理的深刻變革。2024 年《加快構建新型電力系統行動方案》明確提出&#xff0c;到 2027 年需建成全國智慧調度體系&#xff0c;實現新能源消納率突…

自動駕駛中的傳感器技術34——Lidar(9)

補盲lidar設計&#xff1a;機械式和半固態這里不再討論&#xff0c;這里主要針對全固態補盲Lidar進行討論1、系統架構設計采用Flash方案&#xff0c; 設計目標10m10%&#xff0c;實現30m距離的點云覆蓋&#xff0c;同時可以驗證不同FOV鏡頭的設計下&#xff0c;組合為多款產品。…

Originality AI:原創度和AI內容檢測工具

本文轉載自&#xff1a;Originality AI&#xff1a;原創度和AI內容檢測工具 - Hello123工具導航 ** 一、AI 內容誠信管理專家 Originality AI 是面向內容創作者的全棧式質量檢測平臺&#xff0c;整合 AI 內容識別、抄襲查驗、事實核查與可讀性分析四大核心功能&#xff0c;為…

OpenCV圖像平滑處理方法詳解

引言 在數字圖像處理中&#xff0c;圖像平滑是一項基礎而重要的預處理技術。它主要用于消除圖像中的噪聲、減少細節層次&#xff0c;為后續的圖像分析&#xff08;如邊緣檢測、目標識別等&#xff09;創造更好的條件。OpenCV作為最流行的計算機視覺庫之一&#xff0c;提供了多種…

每天兩道算法題:DAY1

題目一&#xff1a;金幣 題目一&#xff1a;金幣 1.題目來源&#xff1a; NOIP2015 普及組 T1&#xff0c;難度紅色&#xff0c;入門簽到題。 2.題目描述&#xff1a; 3.題目解析&#xff1a; 問題轉化&#xff1a;求下面的一個數組的前 k 項和。 4.算法原理&#xff1a; …

C++核心語言元素與構建塊全解析:從語法規范到高效設計

&#x1f4cc; 為什么需要雙維度學習C&#xff1f;核心語言元素 → 掌握標準語法規則&#xff08;避免未定義行為Undefined behavior&#xff09;構建塊&#xff08;Building Blocks&#xff09; → 像搭積木一樣組合功能&#xff08;提升工程能力&#xff09; 例如&#xff1a…

RK3588開發板Ubuntu系統燒錄

Ubuntu22.04——YOLOv8模型訓練到RK3588設備部署和推理 文章中給出了通過ARM設備上面的NPU進行深度學習的模型推理過程,在此之前,我們在收到一塊全新的rk3588開發板后,需要對其進行系統的燒錄,這里以Ubuntu22.04系統為例。 目錄 1.獲取待燒錄系統的鏡像 2.燒錄工具準備 2.1…

AI評測的科學之道:當Benchmark遇上統計學

AI評測的科學之道&#xff1a;當Benchmark遇上統計學 —— 如何客觀評估大模型能力&#xff0c;避免落入數據陷阱 在人工智能尤其是大語言模型&#xff08;LLU&#xff09;爆發式發展的今天&#xff0c;各類模型榜單&#xff08;如Open LLM Leaderboard、LMSys Arena&#xff0…

CSS 基礎入門教程:從零開始學習樣式表

一、CSS 簡介CSS&#xff08;Cascading Style Sheets&#xff0c;層疊樣式表&#xff09;是一種用于描述 HTML 或 XML 等文檔呈現方式的語言。它是現代網頁設計的三大核心技術之一&#xff0c;與HTML&#xff08;結構層&#xff09;和JavaScript&#xff08;行為層&#xff09;…

圖解簡單選擇排序C語言實現

1 簡單選擇排序 簡單選擇排序&#xff08;Simple Selection Sort&#xff09;是一種基礎且直觀的排序算法&#xff0c;其核心思想是通過重復選擇未排序部分中的最小&#xff08;或最大&#xff09;元素&#xff0c;并將其放到已排序部分的末尾&#xff0c;逐步完成整個序列的排…

FPS游戲時,你的電腦都在干什么(CS2)

人物介紹&#xff1a;CPU > 你忠實的處理器 i5-13600KFGPU > 你花大價錢買的顯卡 RTX3060&#xff08;不是自己的配置&#xff0c;自己的是XEON E5GTX1060&#xff0c;測不出來&#xff0c;上面是社區一個好心大哥的數據&#xff0c;較為精準&#xff09;&#…

MySQL完整重置密碼流程(針對 macOS)

MySQL完整重置密碼流程&#xff08;針對 macOS&#xff09; 1. 強制停止 MySQL 服務 sudo /usr/local/mysql/support-files/mysql.server stop sudo killall mysqld mysqld_safe # 確保所有進程停止2. 以安全模式啟動&#xff08;跳過權限驗證&#xff09; sudo /usr/local/my…

Python數據類型轉換詳解:從基礎到實踐

在Python編程中&#xff0c;數據類型轉換是一項基礎且頻繁使用的操作。無論是處理用戶輸入、進行數值計算還是數據處理&#xff0c;都離不開類型轉換。本文將系統介紹Python中的數據類型體系&#xff0c;詳解類型轉換的規則與實踐技巧&#xff0c;幫助你在實際開發中靈活運用。…

智能制造——解讀車企數字化轉型構建高效經營管理數據治理體系【附全文閱讀】

適應人群為車企數字化轉型決策者、數據管理負責人、IT 部門從業者、財務及業務部門管理者。主要內容圍繞車企數字化轉型中經營管理數據治理體系構建展開,核心包括診斷背景(以經營管理數字化為切入點,聚焦財務業務在線化、零點月結等痛點,應對系統與數據問題);現狀診斷(從…

STM32的UART奇偶校驗注意

關鍵點&#xff1a;設置為9位數據位&#xff0c; STM32的UART奇偶校驗注意_stm32串口奇校驗初始化程序-CSDN博客https://blog.csdn.net/JacobFang/article/details/118993643 特此記錄 anlog 2025年8月13日

Origin繪制正態分布直方圖+累積概率圖|科研論文圖表教程(附數據格式模板)

免費查看完整教程(包括數據格式) ↑ ↑ ↑ 目錄 本 期 導 讀 No.1 理解圖形 1 定義 2 圖形特點 3 應用場景 No.2 畫圖教程 1 導入數據,繪制圖形 2 設置繪圖細節 本 期 導 讀 直方圖,以柱狀高低直觀展現各區間數據的分布密度,集中趨勢、離散程度與異常…