我创建了一个 Go 游乐场示例来说明我在说什么。
在示例中,我创建了一个 goroutine,func2,我只想等待通过其通道的输入,并在到达后打印值。
func func2(ch chan int) {
fmt.Println("func2")
v:=<-ch
fmt.Println(v)
}
然后,在一个循环中,我为另一个函数创建 goroutine,这些是 WaitGroup 的一部分。
func func1(ch chan int, wg *sync.WaitGroup) {
fmt.Println("func1")
ch <- 11032
wg.Done()
}
总的来说,我等待候补组。我遇到了死锁,我不知道如何解决它。为了清楚我想要实现的目标,我希望func2在我调用它后保持打开状态,以处理n个值,其中n是我为func1调用的goroutine的数量。我考虑过在 func2 中使用 WaitGroup Wait,但我不希望它阻塞,因为它需要在发送时处理来自 func1 的新数据。
我认为您遇到了僵局,因为您的func2
仅消耗了ch
中的 1个值,然后完成。然后其他func1
goroutines 被困在等待ch
可以写入,他们无法做到这一点,因为没有其他 goroutine 可以从另一端的ch
读取。
由于您希望func2
从ch
到ch
关闭不断使用值,因此您需要在func2
中创建一个循环,如下所示:
func func2(ch chan int) {
fmt.Println("func2")
for v := range ch {
fmt.Println(v)
}
}
这将使func2
保持"活力"并从ch
阅读,直到您在其他地方close(ch)
。在您的示例中,关闭ch
的适当位置可能是wg.Wait()
之后的main
。
如果要确保在程序完成之前查看所有Println
语句的结果,则还应使用一些同步机制来等待func2
完成。否则,main
将在close(ch)
之后立即结束,这可能是也可能不是在func2
打印收到的每个值之前。
一种常见的技术是"完成"通道。例如:
func func2(ch chan int, done chan bool) {
fmt.Println("func2")
for v := range ch {
fmt.Println(v)
}
done <- true
}
在main
:
done := make(chan bool)
go func2(ch, done)
...
wg.Wait()
close(ch)
<-done
使用chan struct{}
(空结构(也很常见,因为空结构不需要内存。
您正在寻找一种在所有值完成流式传输时关闭通道的干净方法。当新值进来时,您可以创建一个新频道并开始在此上流式传输值。这就是我的做法,也许它会有所帮助
var wg sync.WaitGroup
toUpdate := make(chan *someType, BufferSize)
for i := 0; i < BufferSize; i++ {
go processEvents(toUpdate, &wg)
}
// // wait till all the checks have come back
go func(toUpdate chan * someType, group *sync.WaitGroup) {
group.Wait()
close(toCreate)
}(toCreate, toUpdate, &wg)