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