Go互斥体实例

Go互斥体实例

在前面的例子中,我们看到了如何使用原子操作来管理简单的计数器状态。对于更复杂的状态,可以使用互斥体来安全地访问多个goroutine中的数据。

在这个例子中,状态(state)是一个映射。
示例中的互斥将同步访问状态。

我们将跟踪执行的读写操作的数量。

这里将启动100goroutine来对状态执行重复读取,每个goroutine中每毫秒读取一次。

对于每个读取,我们选择一个键来访问,Lock()互斥体以确保对状态的独占访问,读取所选键的值,Unlock()互斥体,并增加readOps计数。

我们还将启动10goroutine来模拟写入,使用与读取相同的模式。

10goroutine在状态和互斥体上工作一秒钟。采集和报告最终操作计数。

收集和报告最终操作计数。用最后的锁状态,显示它是如何结束的。

运行程序显示,我们对互斥同步状态执行了大约90,000次的操作。

所有的示例代码,都放在 F:\worksp\golang 目录下。安装Go编程环境请参考:/tutorial/detail-5562.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]

目录