清華尹成帶你實戰GO案例(1) Go 狀態協程

尹成發表於2018-05-21
Go 狀態協程
在上面的例子中,我們演示瞭如何通過使用mutex來在多個協程之間共享狀態。另外一種方法是使用協程
內建的同步機制來實現。這種基於通道的方法和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() {

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可能導致錯誤。

當然你可以選擇使用任意一種方法,只要你保證這種方法讓你覺得很舒服而且也能保證程式的正確性。



網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN



相關文章