注意 - Go 新手。
我编写了一个多路复用器,它应该将一组 channel 的输出合并为一个。乐于接受建设性的批评。
func Mux(channels []chan big.Int) chan big.Int {
// Count down as each channel closes. When hits zero - close ch.
n := len(channels)
// The channel to output to.
ch := make(chan big.Int, n)
// Make one go per channel.
for _, c := range channels {
go func() {
// Pump it.
for x := range c {
ch <- x
}
// It closed.
n -= 1
// Close output if all closed now.
if n == 0 {
close(ch)
}
}()
}
return ch
}
我正在测试它:
func fromTo(f, t int) chan big.Int {
ch := make(chan big.Int)
go func() {
for i := f; i < t; i++ {
fmt.Println("Feed:", i)
ch <- *big.NewInt(int64(i))
}
close(ch)
}()
return ch
}
func testMux() {
r := make([]chan big.Int, 10)
for i := 0; i < 10; i++ {
r[i] = fromTo(i*10, i*10+10)
}
all := Mux(r)
// Roll them out.
for l := range all {
fmt.Println(l)
}
}
但是我的输出很奇怪:
Feed: 0
Feed: 10
Feed: 20
Feed: 30
Feed: 40
Feed: 50
Feed: 60
Feed: 70
Feed: 80
Feed: 90
Feed: 91
Feed: 92
Feed: 93
Feed: 94
Feed: 95
Feed: 96
Feed: 97
Feed: 98
Feed: 99
{false [90]}
{false [91]}
{false [92]}
{false [93]}
{false [94]}
{false [95]}
{false [96]}
{false [97]}
{false [98]}
{false [99]}
所以我的问题是:
- 我在 Mux 中做错了什么吗?
- 为什么我只能从我的输出 channel 中获取最后 10 个?
- 为什么喂食看起来很奇怪? (每个输入 channel 的第一个,所有最后一个 channel ,然后什么都没有)
- 有更好的方法吗?
我需要所有输入 channel 对输出 channel 具有同等权利 - 即我不能从一个 channel 获得所有输出,然后从下一个 channel 获得所有输出,等等。
对于任何感兴趣的人 - 这是修复和正确(大概)使用 sync.WaitGroup
之后的最终代码
import (
"math/big"
"sync"
)
/*
Multiplex a number of channels into one.
*/
func Mux(channels []chan big.Int) chan big.Int {
// Count down as each channel closes. When hits zero - close ch.
var wg sync.WaitGroup
wg.Add(len(channels))
// The channel to output to.
ch := make(chan big.Int, len(channels))
// Make one go per channel.
for _, c := range channels {
go func(c <-chan big.Int) {
// Pump it.
for x := range c {
ch <- x
}
// It closed.
wg.Done()
}(c)
}
// Close the channel when the pumping is finished.
go func() {
// Wait for everyone to be done.
wg.Wait()
// Close.
close(ch)
}()
return ch
}
最佳答案
从 Mux
生成的每个 goroutine 最终都从同一个 channel 拉取,因为 c
在循环的每次迭代中得到更新——它们不只是捕获c
的值。如果像这样将 channel 传递给 goroutine,您将获得预期的结果:
for _, c := range channels {
go func(c <-chan big.Int) {
...
}(c)
}
您可以测试此修改here .
另一个可能的问题是您对 n
变量的处理:如果您使用 GOMAXPROCS != 1
运行,您可能有两个 goroutine 试图更新它一次。 sync.WaitGroup
类型是等待 goroutines 完成的更安全的方式。
关于go - channel 多路复用器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19192377/