# Go 狀態協程
在上面的例子中,我們演示了如何通過使用mutex來在多個協程之間共享狀態。另外一種方法是使用協程內置的同步機制來實現。這種基于通道的方法和Go的通過消息共享內存,保證每份數據為單獨的協程所有的理念是一致的。
```go
package main
import (
"fmt"
"math/rand"
"sync/atomic"
"time"
)
// 在這個例子中,將有一個單獨的協程擁有這個狀態。這樣可以
// 保證這個數據不會被并行訪問所破壞。為了讀寫這個狀態,其
// 他的協程將向這個協程發送信息并且相應地接受返回信息。
// 這些`readOp`和`writeOp`結構體封裝了這些請求和回復
type readOp struct {
key int
resp chan int
}
type writeOp struct {
key int
val int
resp chan bool
}
func main() {
// 我們將計算我們執行了多少次操作
var ops int64 = 0
// reads和writes通道將被其他協程用來從中讀取或寫入數據
reads := make(chan *readOp)
writes := make(chan *writeOp)
// 這個是擁有`state`的協程,`state`是一個協程的私有map
// 變量。這個協程不斷地`select`通道`reads`和`writes`,
// 當有請求來臨的時候進行回復。一旦有請求,首先執行所
// 請求的操作,然后給`resp`通道發送一個表示請求成功的值。
go func() {
var state = make(map[int]int)
for {
select {
case read := <-reads:
read.resp <- state[read.key]
case write := <-writes:
state[write.key] = write.val
write.resp <- true
}
}
}()
// 這里啟動了100個協程來向擁有狀態的協程請求讀數據。
// 每次讀操作都需要創建一個`readOp`,然后發送到`reads`
// 通道,然后等待接收請求回復
for r := 0; r < 100; r++ {
go func() {
for {
read := &readOp{
key: rand.Intn(5),
resp: make(chan int)}
reads <- read
<-read.resp
atomic.AddInt64(&ops, 1)
}
}()
}
// 我們開啟10個寫協程
for w := 0; w < 10; w++ {
go func() {
for {
write := &writeOp{
key: rand.Intn(5),
val: rand.Intn(100),
resp: make(chan bool)}
writes <- write
<-write.resp
atomic.AddInt64(&ops, 1)
}
}()
}
// 讓協程運行1秒鐘
time.Sleep(time.Second)
// 最后輸出操作數量ops的值
opsFinal := atomic.LoadInt64(&ops)
fmt.Println("ops:", opsFinal)
}
```
運行結果
```
ops: 880578
```
運行這個程序,我們會看到基于協程的狀態管理每秒可以處理800, 000個操作。對于這個例子來講,基于協程的方法比基于mutex的方法更加復雜一點。當然在某些情況下還是很有用的。例如你有很多復雜的協程,而且管理多個mutex可能導致錯誤。
當然你可以選擇使用任意一種方法,只要你保證這種方法讓你覺得很舒服而且也能保證程序的正確性。
- 版權
- 內容
- Go常量
- Go變量
- Go 數值
- Go 數組
- Go 字典
- Go 函數定義
- Go 方法
- Go 結構體
- Go 閉包函數
- Go 接口
- Go 字符串操作函數
- Go 字符串格式化
- Go 自定義排序
- Go Base64編碼
- Go Defer
- Go Exit.md
- Go for循環
- Go if..else if..else 條件判斷
- Go JSON支持
- Go Line Filters
- Go 狀態協程
- Go Panic
- Go range函數
- Go SHA1 散列
- Go String與Byte切片之間的轉換
- Go Switch語句
- Go URL解析
- Go 遍歷通道
- Go 并行功能
- Go 并行通道Channel
- Go 超時
- Go 錯誤處理
- Go 打點器
- Go 遞歸函數
- Go 讀取文件
- Go 工作池
- Go 關閉通道
- Go 函數多返回值
- Go 函數回調
- Go 函數命名返回值
- Go 互斥
- Go 環境變量
- Go 集合功能
- Go 計時器
- Go 進程觸發
- Go 進程執行
- Go hello world
- Go 可變長參數列表
- Go 命令行參數
- Go 命令行參數標記
- Go 排序
- Go 切片
- Go 請求處理頻率控制
- Go 時間
- Go 時間戳
- Go 時間格式化和解析
- Go 數字解析
- Go 隨機數
- Go 通道的同步功能
- Go 通道方向
- Go 通道緩沖
- Go 通道選擇Select
- Go 寫入文件
- Go 信號處理
- Go 原子計數器
- Go 正則表達式
- Go 指針