網站首頁 編程語言 正文
并發安全和鎖
有時候在Go代碼中可能會存在多個goroutine同時操作一個資源(臨界區),這種情況會發生競態問題(數據競態)。類比現實生活中的例子有十字路口被各個方向的的汽車競爭;還有火車上的衛生間被車廂里的人競爭。
舉個例子:
var x int64 var wg sync.WaitGroup func add() { for i := 0; i < 5000; i++ { x = x + 1 } wg.Done() } func main() { wg.Add(2) go add() go add() wg.Wait() fmt.Println(x) }
上面的代碼中我們開啟了兩個goroutine去累加變量x的值,這兩個goroutine在訪問和修改x變量的時候就會存在數據競爭,導致最后的結果與期待的不符。
互斥鎖
import ( "fmt" "sync" ) var lock sync.Mutex lock.Lock() // 加鎖 lock.Unlock() // 解鎖
互斥鎖是一種常用的控制共享資源訪問的方法,它能夠保證同時只有一個goroutine可以訪問共享資源。Go語言中使用sync包的Mutex類型來實現互斥鎖。 使用互斥鎖來修復上面代碼的問題:
var x int64 var wg sync.WaitGroup var lock sync.Mutex func add() { for i := 0; i < 5000; i++ { lock.Lock() // 加鎖 x = x + 1 lock.Unlock() // 解鎖 } wg.Done() } func main() { wg.Add(2) go add() go add() wg.Wait() fmt.Println(x) }
使用互斥鎖能夠保證同一時間有且只有一個goroutine進入臨界區,其他的goroutine則在等待鎖;當互斥鎖釋放后,等待的goroutine才可以獲取鎖進入臨界區,多個goroutine同時等待一個鎖時,喚醒的策略是隨機的。
讀寫互斥鎖
import ( "fmt" "sync" ) var rwlock sync.RWMutex rwlock.Lock() // 加寫鎖 rwlock.Unlock() // 解寫鎖
互斥鎖是完全互斥的,但是有很多實際的場景下是讀多寫少的,當我們并發的去讀取一個資源不涉及資源修改的時候是沒有必要加鎖的,這種場景下使用讀寫鎖是更好的一種選擇。讀寫鎖在Go語言中使用sync包中的RWMutex類型。
讀寫鎖分為兩種:讀鎖和寫鎖。當一個goroutine獲取讀鎖之后,其他的goroutine如果是獲取讀鎖會繼續獲得鎖,如果是獲取寫鎖就會等待;當一個goroutine獲取寫鎖之后,其他的goroutine無論是獲取讀鎖還是寫鎖都會等待。
讀寫鎖示例:
var ( x int64 wg sync.WaitGroup lock sync.Mutex rwlock sync.RWMutex ) func write() { // lock.Lock() // 加互斥鎖 rwlock.Lock() // 加寫鎖 x = x + 1 time.Sleep(10 * time.Millisecond) // 假設讀操作耗時10毫秒 rwlock.Unlock() // 解寫鎖 // lock.Unlock() // 解互斥鎖 wg.Done() } func read() { // lock.Lock() // 加互斥鎖 rwlock.RLock() // 加讀鎖 time.Sleep(time.Millisecond) // 假設讀操作耗時1毫秒 rwlock.RUnlock() // 解讀鎖 // lock.Unlock() // 解互斥鎖 wg.Done() } func main() { start := time.Now() for i := 0; i < 10; i++ { wg.Add(1) go write() } for i := 0; i < 1000; i++ { wg.Add(1) go read() } wg.Wait() end := time.Now() fmt.Println(end.Sub(start)) }
需要注意的是讀寫鎖非常適合讀多寫少的場景,如果讀和寫的操作差別不大,讀寫鎖的優勢就發揮不出來。
原文鏈接:https://www.cnblogs.com/guyouyin123/p/15148203.html
相關推薦
- 2022-09-15 Python利用psutil實現獲取硬件,網絡和進程信息_python
- 2022-06-29 Python使用scipy進行曲線擬合的方法實例_python
- 2022-12-07 C++?Boost?Array與Unordered使用介紹_C 語言
- 2022-10-24 C語言控制進程之進程等待詳解_C 語言
- 2022-10-01 python實現圖像增強算法_python
- 2022-09-02 Redis?單機安裝和哨兵模式集群安裝的實現_Redis
- 2022-10-29 線性回歸(基于python的理論與實現)的RuntimeWaring溢出問題
- 2022-05-08 jquery實現淘寶詳情頁選擇套餐_jquery
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支