Mutexes {.en}

互斥 {.zh}

::: {.en} In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple goroutines. :::

::: {.zh}

在前面的例子中,我们看到了如何使用[atomic operations](原子计数器)管理simplecounter状态。对于更复杂的状态,我们可以使用 [mutex](http://en.wikipedia.org/wiki/Mutual_exclusion )</ em>以安全地访问多个goroutine中的数据。

:::

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "sync"
  6. "sync/atomic"
  7. "time"
  8. )
  9. func main() {

::: {.en} For our example the state will be a map. :::

::: {.zh}

对于我们的例子,state将是一张地图。

:::

  1. var state = make(map[int]int)

::: {.en} This mutex will synchronize access to state. :::

::: {.zh}

这个mutex将同步访问state

:::

  1. var mutex = &sync.Mutex{}

::: {.en} We’ll keep track of how many read and write operations we do. :::

::: {.zh}

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

:::

  1. var readOps uint64
  2. var writeOps uint64

::: {.en} Here we start 100 goroutines to execute repeated reads against the state, once per millisecond in each goroutine. :::

::: {.zh}

在这里,我们启动100个goroutines来执行针对状态的重复读取,每毫秒一次。

:::

  1. for r := 0; r < 100; r++ {
  2. go func() {
  3. total := 0
  4. for {

::: {.en} 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. :::

::: {.zh}

对于每次读取,我们选择一个键来访问,Lock()``mutex以确保对state的唯一访问,读取所选键的值,’解锁()互斥锁,并递增'readOps计数。

:::

  1. key := rand.Intn(5)
  2. mutex.Lock()
  3. total += state[key]
  4. mutex.Unlock()
  5. atomic.AddUint64(&readOps, 1)

::: {.en} Wait a bit between reads. :::

::: {.zh}

在读取之间稍等一下。

:::

  1. time.Sleep(time.Millisecond)
  2. }
  3. }()
  4. }

::: {.en} We’ll also start 10 goroutines to simulate writes, using the same pattern we did for reads. :::

::: {.zh}

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

:::

  1. for w := 0; w < 10; w++ {
  2. go func() {
  3. for {
  4. key := rand.Intn(5)
  5. val := rand.Intn(100)
  6. mutex.Lock()
  7. state[key] = val
  8. mutex.Unlock()
  9. atomic.AddUint64(&writeOps, 1)
  10. time.Sleep(time.Millisecond)
  11. }
  12. }()
  13. }

::: {.en} Let the 10 goroutines work on the state and mutex for a second. :::

::: {.zh}

让10个goroutines在statemutex上工作一秒钟。

:::

  1. time.Sleep(time.Second)

::: {.en} Take and report final operation counts. :::

::: {.zh}

获取并报告最终操作计数。

:::

  1. readOpsFinal := atomic.LoadUint64(&readOps)
  2. fmt.Println("readOps:", readOpsFinal)
  3. writeOpsFinal := atomic.LoadUint64(&writeOps)
  4. fmt.Println("writeOps:", writeOpsFinal)

::: {.en} With a final lock of state, show how it ended up. :::

::: {.zh}

最后锁定state,显示它是如何结束的。

:::

  1. mutex.Lock()
  2. fmt.Println("state:", state)
  3. mutex.Unlock()
  4. }

::: {.en} Running the program shows that we executed about 90,000 total operations against our mutex-synchronized state. :::

::: {.zh}

运行程序表明我们对mutex-synchronizedstate执行了大约90,000个操作。

:::

  1. $ go run mutexes.go
  2. readOps: 83285
  3. writeOps: 8320
  4. state: map[1:97 4:53 0:33 2:15 3:2]

::: {.en} Next we’ll look at implementing this same state management task using only goroutines and channels. :::

::: {.zh}

接下来,我们将仅使用goroutines和channel来实现同样的状态管理任务。

:::