go - 关闭由 channel 链接的 goroutine 链的优雅方法是什么?

标签 go channel goroutine

我是一名围棋学习者。为了更好地理解 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/

相关文章:

http - 在 Go 中读取请求负载?

go - 当没有 channel 准备好被读取时如何什么都不做?

go - Go slice 索引符号背后的想法是什么?

Golang 包导入周期不允许

go - 如何创建一个只接收 channel 的 channel ?

javascript - 带有手动信号的 WebRTC 数据通道的完整示例

methods - 如何获取并发方法

在单独的 goroutine 中显示进度的 HTTP 服务器

go - 在 Goroutine 函数中将数组作为值传递没有任何作用

go - 如何正确处理 runtime.Caller(0) 上的错误