我是一名围棋学习者。为了更好地理解 channel 和 goroutine 的维护和供给,我正在尝试构建一个 Sieve of Eratosthenes 作为一组通过 channel 连接到管道中的 goroutine。
这是我目前所拥有的:
// esieve implements a Sieve of Eratosthenes
// as a series of channels connected together
// by goroutines
package main
import "fmt"
func sieve(mine int, inch chan int) {
start := true // First-number switch
ouch := make(chan int) // Output channel for this instance
fmt.Printf("%v\n", mine) // Print this instance's prime
for next := <-inch; next > 0; next = <-inch { // Read input channel
fmt.Printf("%v <- %v\n",mine,next) // (Trace)
if (next % mine) > 0 { // Divisible by my prime?
if start { // No; is it the first number through?
go sieve(next, ouch) // First number - create instance for it
start = false // First time done
} else { // Not first time
ouch <- next // Pass it to the next instance
}
}
}
}
func main() {
lim := 30 // Let's do up to 30
fmt.Printf("%v\n", 2) // Treat 2 as a special case
ouch := make(chan int) // Create the first segment of the pipe
go sieve(3, ouch) // Create the instance for '3'
for prime := 3; prime < lim; prime += 2 { // Generate 3, 5, ...
fmt.Printf("Send %v\n", prime) // Trace
ouch <- prime // Send it down the pipe
}
}
就目前而言,它运行良好。
但是,当我完成主循环时,main
在所有仍在 sieve
实例管道中的数字传播到最后之前退出。
让主例程等待一组 goroutine(它只“知道”第一个 goroutine)完成的最简单、最优雅或普遍接受的方法是什么?
最佳答案
至于你的标题问题,当你不再需要它们时杀死它们: 您可以使用 Done 习惯用法。从关闭的 channel 中读取会产生零值。
创建一个新 channel 完成
。当从这个 channel 读取成功时,goroutines 知道他们应该退出。当您拥有所需的所有值时,关闭 main 中的 channel 。
检查您是否可以从 channel 读取 done
,然后通过返回退出,或者在可用时从下一个 channel 读取。这部分替换了 for 循环中对 next
的赋值:
select {
case <-done:
return
case next = <- inch:
}
通过 channel 进行测距也可以,因为关闭该 channel 会退出循环。
至于反过来,你的body问题,等待一组goroutines完成:
使用sync.WaitGroup
。
var wg sync.WaitGroup
wg.Add(goroutineCount)
当每个 goroutine 完成时:
wg.Done()
或者使用延迟:
defer wg.Done()
等待所有人报告完成:
wg.Wait()
在您的示例中,只需在启动新的 goroutine 时调用 wg.Add(1)
,然后再调用 wg.Done()
并返回。只要您只达到零一次,wg.Wait()
就会按预期工作,因此 wg.Add(1)
在 wg.Done
之前.
关于go - 关闭由 channel 链接的 goroutine 链的优雅方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34831396/