iT邦幫忙

2023 iThome 鐵人賽

DAY 3
0
自我挑戰組

Concurrency in go 讀書心得系列 第 3

3.Race Condition, Atomicity, Memory Access Synchronization

  • 分享至 

  • xImage
  •  

Race Condition

當多個執行緒或goroutine訪問和操作相同的數據,而其最終的操作結果取決於執行的時序,可能導致不可預期或不一致的結果。

想像一下,兩位顧客在同一時間嘗試在線上商店購買僅剩一件的商品。由於系統沒有同時處理這兩個請求的機制,所以它告訴兩位顧客他們都成功地買到了那件商品。然而,實際上店家只有一件商品,這就是一個競態條件的簡單例子。

在Go中,當兩個或多個goroutines同時訪問同一記憶體位置而至少有一個寫入時,就可能會發生這種情況。

例如以下程式碼

package main

import (
	"fmt"
	"sync"
)

var counter int

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			// 以下的兩行程式碼是非原子操作,這會導致race condition。
			// 當多個goroutine同時執行這些指令時,它們可能會讀取同一個`counter`值,
			// 然後都進行加1的操作,這導致`counter`的增加少於1000。
			localCounter := counter // 讀取`counter`的當前值
			localCounter++          // 對本地的變數進行加1操作
			counter = localCounter  // 更新全局的`counter`變數
			wg.Done()
		}()
	}
	wg.Wait()
	fmt.Println(counter) // 這裡的輸出可能小於1000,因為發生了race condition
}

Atomicity(原子性)

原子性參考於操作是不可分割的。這意味著當一個操作開始時,它將不會被其他的操作打斷,直到它完成為止。在我們前面的線上商店的例子中,如果購買操作是原子的,那麼當一個顧客嘗試購買最後一件商品時,另一個顧客的請求將會等待,直到第一個操作完成。

Go提供了一個sync/atomic包,這個包提供了基本的原子記憶體操作。使用這些原子操作可以確保記憶體更新的完整性,從而避免race condition。
不過,在Go中最常見的方法是使用sync.Mutex或sync.RWMutex。當goroutine想要訪問特定的數據時,它會先鎖定(lock)它。只有當鎖被釋放時,其他的goroutines才能訪問那段數據。

Memory Access Synchronization:

Memory Access Synchronization是關於當多個執行緒或goroutines訪問和修改共享資源時,確保數據完整性和一致性的過程。在多執行緒的程式中,如果沒有正確同步記憶體訪問,可能會導致不可預期的結果,這就是所謂的競態條件。

sync.Mutex是Go提供的一種基本的鎖機制,用於確保同一時刻只有一個goroutine能夠訪問某段程式碼或資源,從而達到Memory Access Synchronization的目的。在上述程式中,我們使用mu.Lock()mu.Unlock()來確保對counter的原子性操作,從而避免race condition。
第一個範例可以修改如下

package main

import (
	"fmt"
	"sync"
)

var counter int
var mu sync.Mutex // 增加一個mutex來保護`counter`

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			// 使用mu.Lock()和mu.Unlock()來確保counter的原子性操作
			mu.Lock() // 在更改`counter`之前鎖定

			// 由於我們已經鎖定了對`counter`的訪問,現在只有一個goroutine可以同時修改它,
			// 這確保了Memory Access Synchronization。
			counter++

			mu.Unlock() // 更新完`counter`後解鎖
			wg.Done()
		}()
	}
	wg.Wait()
	fmt.Println(counter) // 此時,輸出應該確實為1000
}

上一篇
2.Concurrency ? Parallelism?
下一篇
4.Deadlocks, Livelocks, and Starvation
系列文
Concurrency in go 讀書心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言