我怎样才能拥有一个 goroutine 函数来等待来自多个其他函数的值?
How can I have a single goroutine function that waits for values from multiple others?
我创建了一个 Go playground sample 来说明我在说什么。
在这个例子中,我创建了一个 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()
}
在主要部分,我等待 WaitGroup。我 运行 陷入了僵局,我不确定如何解决它。为了清楚我要实现的目标,我希望 func2 在我调用它后作为线程保持打开状态,以处理 n 个值,其中 n 是我为 func1 调用的 goroutines 的数量。我考虑过在 func2 中使用 WaitGroup Wait,但我不希望它阻塞,因为它需要在发送新数据时处理来自 func1 的新数据。
您正在寻找的是一种在所有值流过后关闭通道的简洁方法。当新值出现时,您可以创建一个新频道并开始在其上流式传输值。我就是这样做的,也许有帮助
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)
我认为您陷入了僵局,因为您的 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
"alive" 并从 ch
读取,直到您在其他地方执行 close(ch)
。在您的示例中关闭 ch
的适当位置可能是 wg.Wait()
之后的 main
。
如果您希望确保在程序完成之前看到所有 Println
语句的结果,您还应该使用某种同步机制来等待 func2
完成。否则 main
将在 close(ch)
之后立即结束, 可能会也可能不会 在 func2
打印它收到的每个值之前。
一个常用的技术是 "done" 通道。例如:
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{}
(空结构)也很常见,因为空结构不需要内存。
我创建了一个 Go playground sample 来说明我在说什么。
在这个例子中,我创建了一个 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()
}
在主要部分,我等待 WaitGroup。我 运行 陷入了僵局,我不确定如何解决它。为了清楚我要实现的目标,我希望 func2 在我调用它后作为线程保持打开状态,以处理 n 个值,其中 n 是我为 func1 调用的 goroutines 的数量。我考虑过在 func2 中使用 WaitGroup Wait,但我不希望它阻塞,因为它需要在发送新数据时处理来自 func1 的新数据。
您正在寻找的是一种在所有值流过后关闭通道的简洁方法。当新值出现时,您可以创建一个新频道并开始在其上流式传输值。我就是这样做的,也许有帮助
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)
我认为您陷入了僵局,因为您的 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
"alive" 并从 ch
读取,直到您在其他地方执行 close(ch)
。在您的示例中关闭 ch
的适当位置可能是 wg.Wait()
之后的 main
。
如果您希望确保在程序完成之前看到所有 Println
语句的结果,您还应该使用某种同步机制来等待 func2
完成。否则 main
将在 close(ch)
之后立即结束, 可能会也可能不会 在 func2
打印它收到的每个值之前。
一个常用的技术是 "done" 通道。例如:
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{}
(空结构)也很常见,因为空结构不需要内存。