我将使用一个hacky低效的素数查找器来使这个问题更具体。
假设我们的主要功能是激发了一堆“工人”goroutines。他们会将结果报告给一个印有它们的通道。但是不是每个工作人员都会报告,所以我们不能使用计数器来知道上一个工作何时完成。或者有办法吗?
对于具体的例子,在这里,main触发goroutines以检查值2 ... 1000是否为素数(是的,我知道它是低效的)。
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
go func () {
for {
fmt.Print(" ", <- c)
}
}()
for n := 2; n < 1000; n++ {
go printIfPrime(n, c)
}
time.Sleep(2 * time.Second) // <---- THIS FEELS WRONG
}
func printIfPrime(n int, channel chan int) {
for d := 2; d * d <= n; d++ {
if n % d == 0 {
return
}
}
channel <- n
}
我的问题是我不知道如何在合适的时间可靠地阻止它。我尝试在main
结束时添加一个睡眠并且它可以工作(但可能需要很长时间,而且这无法编写并发代码!)。我想知道是否有办法通过频道发送停止信号,以便main
可以在正确的时间停止。
这里的诀窍是我不知道会有多少工人回应。
这是不可能的还是有一个很酷的伎俩?
(如果这个主要例子的答案很好,那很好。我可以概括。或者可能没有。也许这是特定于应用程序的?)
答案 0 :(得分:3)
使用WaitGroup
。
以下代码使用两个WaitGroup。主函数使用wgTest
等待print_if_prime
函数完成。一旦完成,它将关闭通道以打破打印goroutine中的for循环。主函数使用wgPrint
等待打印完成。
package main
import (
"fmt"
"sync"
)
func main() {
c := make(chan int)
var wgPrint, wgTest sync.WaitGroup
wgPrint.Add(1)
go func(wg *sync.WaitGroup) {
defer wg.Done()
for n := range c {
fmt.Print(" ", n)
}
}(&wgPrint)
for n := 2; n < 1000; n++ {
wgTest.Add(1)
go print_if_prime(&wgTest, n, c)
}
wgTest.Wait()
close(c)
wgPrint.Wait()
}
func print_if_prime(wg *sync.WaitGroup, n int, channel chan int) {
defer wg.Done()
for d := 2; d*d <= n; d++ {
if n%d == 0 {
return
}
}
channel <- n
}