在前面的例子中,我們看到了如何使用原子操作來(lái)管理簡(jiǎn)單的計(jì)數(shù)器狀態(tài)。對(duì)于更復(fù)雜的狀態(tài),可以使用互斥體來(lái)安全地訪問(wèn)多個(gè)goroutine中的數(shù)據(jù)。
在這個(gè)例子中,狀態(tài)(state)是一個(gè)映射。
示例中的互斥將同步訪問(wèn)狀態(tài)。
我們將跟蹤執(zhí)行的讀寫操作的數(shù)量。
這里將啟動(dòng)100個(gè)goroutine來(lái)對(duì)狀態(tài)執(zhí)行重復(fù)讀取,每個(gè)goroutine中每毫秒讀取一次。
對(duì)于每個(gè)讀取,我們選擇一個(gè)鍵來(lái)訪問(wèn),Lock()互斥體以確保對(duì)狀態(tài)的獨(dú)占訪問(wèn),讀取所選鍵的值,Unlock()互斥體,并增加readOps計(jì)數(shù)。
我們還將啟動(dòng)10個(gè)goroutine來(lái)模擬寫入,使用與讀取相同的模式。
讓10個(gè)goroutine在狀態(tài)和互斥體上工作一秒鐘。采集和報(bào)告最終操作計(jì)數(shù)。
收集和報(bào)告最終操作計(jì)數(shù)。用最后的鎖狀態(tài),顯示它是如何結(jié)束的。
運(yùn)行程序顯示,我們對(duì)互斥同步狀態(tài)執(zhí)行了大約90,000次的操作。
所有的示例代碼,都放在
F:\worksp\golang目錄下。安裝Go編程環(huán)境請(qǐng)參考: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()
}
執(zhí)行上面代碼,將得到以下輸出結(jié)果 -
F:\worksp\golang>go run mutexes.go
readOps: 84546
writeOps: 8473
state: map[0:99 3:3 4:62 1:18 2:89]