網站首頁 編程語言 正文
代碼中的加鎖操作因為涉及內核態的上下文切換會比較耗時、代價比較高。針對基本數據類型我們還可以使用原子操作來保證并發安全,因為原子操作是Go語言提供的方法它在用戶態就可以完成,因此性能比加鎖操作更好。Go語言中原子操作由內置的標準庫sync/atomic
提供。
大多數情況下我們都是針對基本數據類型進行數據操作,能不加鎖就不加鎖。
首先很多人都不相信基本類型并發修改會出現競態問題。不妨嘗試一下,并發加一。
var wg sync.WaitGroup for i := 0; i < 10000; i++ { wg.Add(1) go func () { defer wg.Done() xInt32++ }() } wg.Wait() print(xInt32)
無論輸出多少次都無法達到10000
,之所以如此就是因為此處的加1操作并不是原子的,都是先取當前值,加1,再賦值,會出現覆蓋的情況。
修改
修改是最常用到的。
func modify(delta int32) { atomic.AddInt32(&xInt32, delta) atomic.AddInt64(&xInt64, int64(delta)) atomic.AddUint32(&xuInt32, uint32(delta)) atomic.AddUint64(&xuInt64, uint64(delta)) }
我們忽略了Uintptr
的討論,這是內存地址的整數表示,是用來存地址內容的,暫時沒有遇到過指針的數據計算。
var wg sync.WaitGroup for i := 0; i < 10000; i++ { wg.Add(1) go func () { defer wg.Done() //xInt32++ modify(1) }() } wg.Wait() print(xInt32)
改為原子操作后,發現每次運行都可以得到預期的結果10000
,
賦值與讀取
在并發情況下,讀取到某個變量后,在使用時變量內容可能會被篡改,所以使用原子讀取。 在并發情況下,為某個變量賦值的時候,必須要防止讀取到寫入一半的錯誤值,所以要用原子寫入。
var xInt32 int32 atomic.StoreInt32(&xInt32, 100) println(xInt32) v := atomic.LoadInt32(&xInt32) println(v)
輸出
100
100
就目前而言,原子讀寫都是為了防止讀寫一半導致數據錯誤,但我無法復現這種錯誤的場景,假如你可以復現請在本文底部放留言。
var v atomic.Value v.Store([]int{}) fmt.Println(v.Load().([]int))
也可以存儲其他任意類型,但如果使用到類似append
擴容原變量的語句,而不是使用直接替換的話,原子操作也是會失效的。
比較并交換
以下是節選自《Go并發編程實戰》一書中的例子,比較并交換(Compare And Swap)簡稱CAS,是樂觀鎖的核心思想,所以簡單介紹一下。
var xInt32 int32 for { v := atomic.LoadInt32(&xInt32) if atomic.CompareAndSwapInt32(&xInt32, v, v+100) { break } } print(xInt32)
- 這里一種無鎖的結構,是一種思路,在需要改變數據的時候,反復判斷數據是否和原數據一致
- 一致時替換,不一致時說明被它處修改,則跳過
- 在不創建互斥量和不形成臨界區的情況下,完成并發安全的值替換操作。
小結
1.最常用原子操作中的修改、基本類型的值賦值,其他不常用
2.在其他類型出現并發的時候盡可能使用sync
包提供的并發安全的類型,下一節講。
3.通過通信共享內存;不要通過共享內存進行通信。盡量使用通道。
原文鏈接:https://juejin.cn/post/7182058346445766711
相關推薦
- 2022-12-10 C++中使用正則匹配問題_C 語言
- 2022-09-20 C#中使用async和await實現異步Udp通訊的示例代碼_C#教程
- 2022-07-28 Python中schedule模塊關于定時任務使用方法_python
- 2022-07-18 Uniapp中調整web-view的高度、獲取當前的web-view頁面URL
- 2022-10-19 C#實現自動生成電子印章_C#教程
- 2022-09-06 golang?gin框架實現大文件的流式上傳功能_Golang
- 2022-11-28 golang進程在docker中OOM后hang住問題解析_Golang
- 2021-12-20 使用Docker構建開發環境的方法步驟(?Windows和mac)_docker
- 最近更新
-
- 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同步修改后的遠程分支