2 回答

TA貢獻1821條經驗 獲得超5個贊
您有多個可以同時運行的工作人員,并且所有工作人員都可以同時嘗試和發(fā)出請求。由于requestChan
是無緩沖的,它們都阻塞等待讀取器同步并接受他們的請求。
您有多個生成器,它們將通過 與請求者同步requestChan
,生成結果,然后阻塞無緩沖,generatorChan
直到工作人員讀取結果。請注意,它可能是不同的工人。
沒有額外的同步,所以其他一切都是不確定的。
一個生成器可以處理所有請求。
生成器可以獲取請求并
seq
在任何其他生成器有機會運行之前通過遞增。只有一個處理器,這甚至是可能的。所有的生成器都可以獲取請求,并且最終都想要
seq
在完全相同的時間遞增,從而導致各種問題。工作人員可以從他們碰巧發(fā)送到或來自完全不同的生成器的同一生成器中獲得響應。
通常,如果不添加同步來強制執(zhí)行這些行為中的一種,則無法確保其中任何一種行為確實發(fā)生。
請注意,對于數(shù)據(jù)競爭,這本身就是另一個非確定性事件。有可能獲得任意值、程序崩潰等。假設在競爭條件下該值可能只是被一個或一些這樣的相對無害的結果關閉是不安全的。
對于試驗,您能做的最好的事情就是加速GOMAXPROCS
。通過環(huán)境變量(例如類似env GOMAXPROCS=16 go run foo.go
或env GOMAXPROCS=16 ./foo
之后go build
)或runtime.GOMAXPROCS(16)
從您的程序調用。默認值為 1,這意味著可能會隱藏數(shù)據(jù)競爭或其他“奇怪”行為。
您還可以通過在不同的點添加調用runtime.Gosched
或time.Sleep
在不同的點上來影響一些事情。
如果您使用競爭檢測器(例如使用go run -race foo.goo
或go build -race
),您還可以看到數(shù)據(jù)競爭。程序不僅應該在退出時顯示“Found 1 data race(s)”,而且還應該在首次檢測到競爭時轉儲大量帶有堆棧跟蹤的詳細信息。
這是用于實驗的代碼的“清理”版本:
package main
import (
"log"
"sync"
"sync/atomic"
)
var seq uint64 = 0
var generatorChan = make(chan uint64)
var requestChan = make(chan uint64)
func generator(genID int) {
for reqID := range requestChan {
// If you want to see a data race:
//seq = seq + 1
// Else:
s := atomic.AddUint64(&seq, 1)
log.Printf("Gen: %2d, from %3d", genID, reqID)
generatorChan <- s
}
}
func worker(id int, work *sync.WaitGroup) {
defer work.Done()
for i := 0; i < 5; i++ {
requestChan <- uint64(id)
log.Printf("\t\t\tWorker: %3d got %4d", id, <-generatorChan)
}
}
func main() {
log.SetFlags(log.Lmicroseconds)
const (
numGen = 20
numWorker = 200
)
var wg sync.WaitGroup
for i := 0; i < numGen; i++ {
go generator(i)
}
wg.Add(numWorker)
for i := 0; i < numWorker; i++ {
go worker(i, &wg)
}
wg.Wait()
close(requestChan)
}
Playground(但請注意,playground 上的時間戳沒有用,調用runtime.MAXPROCS可能沒有任何作用)。進一步注意,playground 會緩存結果,因此重新運行完全相同的程序將始終顯示相同的輸出,您需要進行一些小的更改或僅在您自己的機器上運行它。
很多小的變化,比如關閉生成器,使用logvsfmt因為前者可以保證并發(fā)性,消除數(shù)據(jù)競爭,使輸出看起來更好等。

TA貢獻1820條經驗 獲得超10個贊
渠道類型
通道為并發(fā)執(zhí)行函數(shù)提供了一種機制,通過發(fā)送和接收指定元素類型的值來進行通信。未初始化通道的值為 nil。
可以使用內置函數(shù) make 創(chuàng)建一個新的初始化通道值,該函數(shù)將通道類型和可選容量作為參數(shù):
make(chan?int,?100)容量(以元素數(shù)為單位)設置通道中緩沖區(qū)的大小。如果容量為零或不存在,則通道沒有緩沖,只有當發(fā)送方和接收方都準備好時,通信才能成功。否則,如果緩沖區(qū)未滿(發(fā)送)或非空(接收),則通道被緩沖并且通信成功而不會阻塞。一個 nil 通道永遠不會準備好進行通信。
您正在使用無緩沖通道來限制通道通信。
例如,
generatorChan?=?make(chan?uint64) requestChan?=?make(chan?uint64)
- 2 回答
- 0 關注
- 258 瀏覽
添加回答
舉報