[英]Golang Multiple Channel Write/Receive Ordering
我的具體問題是,我有一個無緩沖的通道,並且正在生成多個帶有信號量的goroutine來執行工作:
func main() {
sem := make(chan struct{}, 10) // allow ten concurrent parsers
wg := &sync.WaitGroup{}
wg.Add(1)
DoSomething("http://example.com", sem, wg)
wg.Wait()
// all done
}
func DoSomething(u string, sem chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
sem <- struct{}{} // grab
defer func() { <-sem }() // release
var newSomethings []string
// ...
for u := range newSomethings {
wg.Add(1)
go DoSomething(u)
}
}
如果堆棧上有多個DoSomething
goroutine,在sem
寫操作(或在讀操作上相反)中被阻塞,則在發生寫操作時,go例程對寫操作的處理順序如何? 我想這是隨機的,但我可以想象:
我查看了一些資源,但找不到解決方案:
我想知道這是否是未定義的和/或實現相關的,或者是否在go內核中的某個位置找到並定義了此邏輯?
未定義發送操作中阻塞的goroutine的服務順序,但將其實現為FIFO。 您可以在runtime / chan.go中看到實現,該實現使用鏈接列表跟蹤通道的發送者和接收者。
我們可以嘗試制作一個顯示有效排序的示例,如下所示:
func main() {
ch := make(chan int)
ready := make(chan int)
for i := 0; i < 10; i++ {
i := i
go func() {
ready <- 1
ch <- i
}()
<-ready
runtime.Gosched()
}
for i := 0; i < 10; i++ {
v := <-ch
if i != v {
panic("out of order!")
}
fmt.Println(v)
}
}
https://play.golang.org/p/u0ukR-5Ptw4
從技術上來說,這仍然是不正確的,因為無法觀察到發送操作上的阻塞,因此在下一行上的ready
發送與發送到ch
之間仍然存在競爭。 我們可以嘗試使用此處的runtime.Gosched
調用,甚至time.Sleep
消除這種time.Sleep
,但是如果沒有顯式同步,就無法保證“先發生”關系。
無論如何,這都會使goroutine排隊,並顯示預期的輸出順序,如果尚未將它們排隊,則更有可能亂序處理這些值。
通過此示例可以看到,我們無法真正確定goroutine排隊的順序,它幾乎總是不確定的,因此在實踐中通常沒有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.