簡體   English   中英

Golang多通道寫入/接收排序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM