當某種東西被認為是原子性的或者具有原子性的時候,這意味著在它運行的環境中,它是不可分割的或不可中斷的。
那么這到底意味著什么,為什么在使用并發代碼時知道這很重要?
第一件非常重要的事情就是了解“上下文(context)”這個詞。在某個特定的上下文中,有的操作可能是原子的,有的可能不是。 在你的流程環境中,原子狀態的操作在操作系統環境中可能不是原子操作; 在操作系統環境中是原子的操作在你的機器環境中可能不是原子的; 并且在機器上下文中是原子的操作在應用程序上下文中可能不是原子的。 換句話說,操作的原子性可以根據當前定義的范圍而改變。 清醒的認識到這個事實對你程序的利弊是非常重要的!
在考慮原子性時,經常需要做的第一件事是定義上下文或作用域,這個操作將被視為原子性的。這是思考程序的基礎。
>2006年,游戲公司Blizzard成功起訴了MDY Industries 600萬美元源于其開發的名為“滑翔機”的程序,該程序可在沒有用戶干預的情況下自動操作他們的游戲“魔獸世界”。 這些類型的程序通常被稱為“機器人外掛”。
當時,魔獸世界有一個反作弊程序叫做“守望者“,它可以在你玩游戲的任何時候運行。除此之外,守望者將掃描主機的內存并運行啟發式查找似乎用于作弊的程序。
利用原子上下文的概念,滑翔機成功避免了守望者的這種檢查。 守望者認為掃描機器上的內存是一種原子操作,但在開始掃描之前,滑翔機利用硬件中斷來隱藏自己!守望者守護進程的內存掃描在進程的上下文中是原子的,但不在操作系統的上下文中。
現在讓我們看一下術語“不可分割”和“不可中斷”。這些術語意味著在你定義的上下文中,原子的東西將在整個過程中發生,而不會同時發生任何事情。 這讓人有點糊涂,所以我們來看一個例子:
```
i++
```
這是一個任何人都可以明白的簡單代碼,但它很容易證明原子性的概念。 它可能看起來很原子,但是一個簡單的分析揭示了幾種操作:
* 檢索i的值。
* 增加i的價值。
* 存儲i的值。
盡管這些操作中的每一個都是原子的,但三者的組合可能不是,取決于你的上下文。 這揭示了原子操作的一個有趣特性:將它們結合并不一定會產生更大的原子操作。 創建操作原子取決于你希望它在哪個上下文中處于原子狀態。 如果你的上下文是一個沒有并發進程的程序,那么這個代碼在該上下文中是原子的。 如果你的上下文是一個不會將 i 暴露給其他goroutine的goroutine,那么這個代碼是原子的。
為什么我們如此在意原子性?原子性非常重要,因為如果說某些東西是原子的,那么就隱式地意味著在并發環境中是安全的。這使我們能夠編寫邏輯上正確的程序,并且——我們稍后將看到——甚至可以用作優化并發程序的一種方式。
大多數語句不是原子的,更不用說函數,方法和程序了。如果原子性是組成邏輯上正確的程序關鍵,并且大多數語句不是原子的,那么我們如何調和這兩個問題?稍后我們會深入探討,但總之,我們可以通過采用各種技術來強制原子性。至于如何決定你的代碼的哪些部分需要是原子的,以及需要劃分到什么樣的粒度,我們在下一節繼續討論。
* * * * *
學識淺薄,錯誤在所難免。我是長風,歡迎來Golang中國的群(211938256)就本書提出修改意見。
- 前序
- 誰適合讀這本書
- 章節導讀
- 在線資源
- 第一章 并發編程介紹
- 摩爾定律,可伸縮網絡和我們所處的困境
- 為什么并發編程如此困難
- 數據競爭
- 原子性
- 內存訪問同步
- 死鎖,活鎖和鎖的饑餓問題
- 死鎖
- 活鎖
- 饑餓
- 并發安全性
- 優雅的面對復雜性
- 第二章 代碼建模:序列化交互處理
- 并發與并行
- 什么是CSP
- CSP在Go中的衍生物
- Go的并發哲學
- 第三章 Go的并發構建模塊
- Goroutines
- sync包
- WaitGroup
- Mutex和RWMutex
- Cond
- Once
- Pool
- Channels
- select語句
- GOMAXPROCS
- 結論
- 第四章 Go的并發編程范式
- 訪問范圍約束
- fo-select循環
- 防止Goroutine泄漏
- or-channel
- 錯誤處理
- 管道
- 構建管道的最佳實踐
- 便利的生成器
- 扇入扇出
- or-done-channel
- tee-channel
- bridge-channel
- 隊列
- context包
- 小結
- 第五章 可伸縮并發設計
- 錯誤傳遞
- 超時和取消
- 心跳
- 請求并發復制處理
- 速率限制
- Goroutines異常行為修復
- 本章小結
- 第六章 Goroutines和Go運行時
- 任務調度