當前位置: 首頁>>編程語言>>正文


Go語言教程:互斥鎖

返回Go語言教程首頁

概念簡介

在前麵的例子中,我們看到了如何使用原子操作來管理簡單的計數器。
對於更加複雜的情況,我們可以使用一個互斥鎖
來在 Go 協程間安全的訪問數據。

例程代碼


package main

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

func main() {

    // 在我們的例子中,`state` 是一個 map。
    var state = make(map[int]int)

    // 這裏的 `mutex` 將同步對 `state` 的訪問。
    var mutex = &sync.Mutex{}

    // we'll see later, `ops` will count how many
    // operations we perform against the state.
    // 為了比較基於互斥鎖的處理方式和我們後麵將要看到的其他
    // 方式,`ops` 將記錄我們對 state 的操作次數。
    var ops int64 = 0

    // 這裏我們運行 100 個 Go 協程來重複讀取 state。
    for r := 0; r < 100; r++ {
        go func() {
            total := 0
            for {

                // 每次循環讀取,我們使用一個鍵來進行訪問,
                // `Lock()` 這個 `mutex` 來確保對 `state` 的
                // 獨占訪問,讀取選定的鍵的值,`Unlock()` 這個
                // mutex,並且 `ops` 值加 1。
                key := rand.Intn(5)
                mutex.Lock()
                total += state[key]
                mutex.Unlock()
                atomic.AddInt64(&ops, 1)

                // 為了確保這個 Go 協程不會在調度中餓死,我們
                // 在每次操作後明確的使用 `runtime.Gosched()`
                // 進行釋放。這個釋放一般是自動處理的,像例如
                // 每個通道操作後或者 `time.Sleep` 的阻塞調用後
                // 相似,但是在這個例子中我們需要手動的處理。
                runtime.Gosched()
            }
        }()
    }

    // 同樣的,我們運行 10 個 Go 協程來模擬寫入操作,使用
    // 和讀取相同的模式。
    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.AddInt64(&ops, 1)
                runtime.Gosched()
            }
        }()
    }

    // 讓這 10 個 Go 協程對 `state` 和 `mutex` 的操作
    // 運行 1 s。
    time.Sleep(time.Second)

    // 獲取並輸出最終的操作計數。
    opsFinal := atomic.LoadInt64(&ops)
    fmt.Println("ops:", opsFinal)

    // 對 `state` 使用一個最終的鎖,顯示它是如何結束的。
    mutex.Lock()
    fmt.Println("state:", state)
    mutex.Unlock()
}

執行&輸出


# 運行這個程序,顯示我們對已進行了同步的 `state` 執行了
# 3,500,000 次操作。
$ go run mutexes.go
ops: 3598302
state: map[1:38 4:98 2:23 3:85 0:44]

# 接下來我們將看一下隻使用 Go 協程和通道是如何實現
# 相同的狀態控製任務的。

課程導航

學習上一篇:Go語言教程:原子計數器    學習下一篇:Go語言教程:狀態協程

相關資料

本例程github源代碼:https://github.com/xg-wang/gobyexample/tree/master/examples/mutexes

Go語言互斥鎖

本文由《純淨天空》出品。文章地址: https://vimsky.com/zh-tw/article/4072.html,未經允許,請勿轉載。