簡體   English   中英

Golang 中單個通道的多個發件人

[英]Multiple senders to single channel in Golang

這個概念似乎很容易解釋,但實現起來有點困難(“正確”)。

tl; dr 是我想運行多個將輸出推送到單個通道的函數。

作為示例工作測試(具有多個通道),詳細說明我的問題https://play.golang.org/p/1ztCvPFLXKv

package main

import (
    "fmt"
    "time"
)

type intTest struct {
    ID     int
    Number int
}

func modify1(channelID string, res chan []intTest) {
    s := []intTest{}
    for i := 0; i < 10; i++ {
        fmt.Printf("Adding inside: %s\n", channelID)
        s = append(s, intTest{i, 0})
        time.Sleep(100 * time.Millisecond)
    }
    res <- s
}
func modify2(channelID string, res chan []intTest) {
    s := []intTest{}
    for i := 10; i < 20; i++ {
        fmt.Printf("Adding inside: %s\n", channelID)
        s = append(s, intTest{i, 0})
        time.Sleep(200 * time.Millisecond)
    }
    res <- s
}
func modify3(channelID string, res chan []intTest) {
    s := []intTest{}
    for i := 20; i < 30; i++ {
        fmt.Printf("Adding inside: %s\n", channelID)
        s = append(s, intTest{i, 0})
        time.Sleep(300 * time.Millisecond)
    }
    res <- s
}

func main() {
    channelA := make(chan []intTest)
    channelB := make(chan []intTest)
    channelC := make(chan []intTest)

    go modify1("A", channelA)
    go modify2("B", channelB)
    go modify3("C", channelC)

    b := append(<-channelA, <-channelB...)
    b = append(b, <-channelC...)
    fmt.Println(b)
}

輸出:

Adding inside: C
Adding inside: A
Adding inside: B
..snip..
Adding inside: C
Adding inside: C
Adding inside: C
[{0 0} {1 0} {2 0} {3 0} {4 0} {5 0} {6 0} {7 0} {8 0} {9 0} {10 0} {11 0} {12 0} {13 0} {14 0} {15 0} {16 0} {17 0} {18 0} {19 0} {20 0} {21 0} {22 0} {23 0} {24 0} {25 0} {26 0} {27 0} {28 0} {29 0}]

但是,我想實現這樣的目標: https : //play.golang.org/p/qvC88LwkanY輸出:

Adding inside: C
Adding inside: A
Adding inside: B
..snip
Adding inside: B
Adding inside: A
Adding inside: C
[{0 0} {1 0} {2 0} {3 0} {4 0} {5 0} {6 0} {7 0} {8 0} {9 0}]

但如圖所示,函數 modify2 和 modify3 在視覺上似乎從未被添加。

這是可能的,還是頂部樣本更可行?

我想實現這樣的目標

channelA := make(chan []intTest)
go modify1("A", channelA)
go modify2("B", channelA)
go modify3("C", channelA)

這是可能的,還是頂部樣本更可行?

是的:您可以跨多個 goroutine 使用單個通道——這就是通道的設計目的。

但如圖所示,函數 modify2 和 modify3 在視覺上似乎從未被添加。

您遇到的問題是您只調用了接收運算符一次:

b := append(<-channelA)
fmt.Println(b)

當您的main goroutine 退出時,另外兩個 goroutine 要么被阻塞,等待發送它們的結果,要么仍在構建它們的結果。

如果您將main()函數更改為此,您可以看到如果另一個例程准備接收(因為您使用了無緩沖通道,發送將阻塞,直到接收器准備就緒),所有三個工作器都將通過通道發送它們的結果:

func main() {
    ch := make(chan []intTest)

    go modify1("A", ch)
    go modify2("B", ch)
    go modify3("C", ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

哪些輸出:

Adding inside: C
Adding inside: A
Adding inside: B
Adding inside: A
Adding inside: A
Adding inside: B
Adding inside: C
Adding inside: A
Adding inside: B
Adding inside: A
Adding inside: A
Adding inside: B
Adding inside: C
Adding inside: A
Adding inside: A
Adding inside: B
Adding inside: A
Adding inside: C
Adding inside: A
Adding inside: B
[{0 0} {1 0} {2 0} {3 0} {4 0} {5 0} {6 0} {7 0} {8 0} {9 0}]
Adding inside: C
Adding inside: B
Adding inside: B
Adding inside: C
Adding inside: B
Adding inside: C
Adding inside: B
[{10 0} {11 0} {12 0} {13 0} {14 0} {15 0} {16 0} {17 0} {18 0} {19 0}]
Adding inside: C
Adding inside: C
Adding inside: C
[{20 0} {21 0} {22 0} {23 0} {24 0} {25 0} {26 0} {27 0} {28 0} {29 0}]

然后,您可以更改該代碼以在輸出之前將接收到的元素附加到單個列表中,或者以您喜歡的任何方式格式化接收到的元素。

我認為這幾乎就像彈出一個堆棧然后拉整個堆棧

使用初始化的、未關閉的、緩沖的通道,發送語句將一個元素放入隊列,接收操作從隊列中彈出一個元素並將其返回。 它是先進先出 (FIFO) 順序,所以它是一個隊列而不是一個堆棧。 在上面的例子中,通道是無緩沖的,所以發送必須等待准備接收的 goroutine,接收必須等待准備發送的 goroutine。 Main 也是一個 goroutine。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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