Go互斥體實例

在前面的例子中,我們看到了如何使用原子操作來管理簡單的計數器狀態。對於更復雜的狀態,可以使用互斥體來安全地訪問多個goroutine中的數據。

在這個例子中,狀態(state)是一個映射。
示例中的互斥將同步訪問狀態。

我們將跟蹤執行的讀寫操作的數量。

這裏將啓動100goroutine來對狀態執行重複讀取,每個goroutine中每毫秒讀取一次。

對於每個讀取,我們選擇一個鍵來訪問,Lock()互斥體以確保對狀態的獨佔訪問,讀取所選鍵的值,Unlock()互斥體,並增加readOps計數。

我們還將啓動10goroutine來模擬寫入,使用與讀取相同的模式。

10goroutine在狀態和互斥體上工作一秒鐘。採集和報告最終操作計數。

收集和報告最終操作計數。用最後的鎖狀態,顯示它是如何結束的。

運行程序顯示,我們對互斥同步狀態執行了大約90,000次的操作。

所有的示例代碼,都放在 F:\worksp\golang 目錄下。安裝Go編程環境請參考:http://www.yiibai.com/go/go\_environment.html

mutexes.go的完整代碼如下所示 -

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "sync/atomic"
    "time"
)

func main() {

    // For our example the `state` will be a map.
    var state = make(map[int]int)

    // This `mutex` will synchronize access to `state`.
    var mutex = &sync.Mutex{}

    // We'll keep track of how many read and write
    // operations we do.
    var readOps uint64 = 0
    var writeOps uint64 = 0

    // Here we start 100 goroutines to execute repeated
    // reads against the state, once per millisecond in
    // each goroutine.
    for r := 0; r < 100; r++ {
        go func() {
            total := 0
            for {

                // For each read we pick a key to access,
                // `Lock()` the `mutex` to ensure
                // exclusive access to the `state`, read
                // the value at the chosen key,
                // `Unlock()` the mutex, and increment
                // the `readOps` count.
                key := rand.Intn(5)
                mutex.Lock()
                total += state[key]
                mutex.Unlock()
                atomic.AddUint64(&readOps, 1)

                // Wait a bit between reads.
                time.Sleep(time.Millisecond)
            }
        }()
    }

    // We'll also start 10 goroutines to simulate writes,
    // using the same pattern we did for reads.
    for w := 0; w < 10; w++ {
        go func() {
            for {
                key := rand.Intn(5)
                val := rand.Intn(100)
                mutex.Lock()
                state[key] = val
                mutex.Unlock()
                atomic.AddUint64(&writeOps, 1)
                time.Sleep(time.Millisecond)
            }
        }()
    }

    // Let the 10 goroutines work on the `state` and
    // `mutex` for a second.
    time.Sleep(time.Second)

    // Take and report final operation counts.
    readOpsFinal := atomic.LoadUint64(&readOps)
    fmt.Println("readOps:", readOpsFinal)
    writeOpsFinal := atomic.LoadUint64(&writeOps)
    fmt.Println("writeOps:", writeOpsFinal)

    // With a final lock of `state`, show how it ended up.
    mutex.Lock()
    fmt.Println("state:", state)
    mutex.Unlock()
}

執行上面代碼,將得到以下輸出結果 -

F:\worksp\golang>go run mutexes.go
readOps: 84546
writeOps: 8473
state: map[0:99 3:3 4:62 1:18 2:89]