卡在 golang 中的频道

Stuck with Channels in golang

我需要运行一个函数并行执行多次。
如果即使函数 returns true(在频道上发送 true),那么最终结果应该是 true.

如何使用 goroutines 和通道实现此目的?

// Some performance intensive function
func foo(i int, c chan bool) {
    // do some processing and return either true or false
    c <- true // or false
}

func main() {
    flg := false
    ch := make(chan bool)
    for i := 0; i < 10; i++ {
        go foo(i, ch)
    }
    // If even once foo() returned true then val should be true
    flg = flg || <-ch
}

您可以从 ch 频道开始阅读,并在获得真实结果后将 flg 设置为 true。像这样:

//flg = flg || <- ch
for res := range ch {
    if res {
        flg = true
    }
}

这种方法可行,但有一个严重的缺点 - for 循环无限等待来自通道的新值。停止循环的惯用方法是关闭通道。您可以这样做:运行 一个单独的 goroutine,它将等待所有 goroutine 退出。 Go 提供了一个非常方便的工具来做到这一点 - sync.WaitGroup.

在全局范围内定义它,以便每个 goroutine 都可以访问它:

var (
    wg sync.WaitGroup
)

然后每次启动 goroutine 时,都会再添加一个 goroutine 到等待组:

for i := 0; i < 10; i++ {
    wg.Add(1)   // here
    go foo(i, ch)
}

当 goroutine 完成时它调用 wg.Done 方法来标记它。

func foo(i int, c chan bool) {
    //do some processing and return either true or false
    c <- true   //or false
    wg.Done()   // here
}

然后 sepatate goroutine 等待所有 foo goroutines 退出并关闭通道。 wg.Wait 块,直到全部完成:

 go func() {
    wg.Wait()
    close(ch)
}()

总计:https://play.golang.org/p/8qiuA29-jv

您只从通道接收到一个值(这将是 foo() 调用之一发送的值,无法预测是哪一个),但您想要接收所有。

所以使用一个for循环来接收你在其上发送(发送)的值:

for i := 0; i < 10; i++ {
    flg = flg || <-ch
}

虽然在你的情况下循环直到收到一个 true 值就足够了,因为这将决定 flg 的最终值,但仍然建议接收所有其他值剩余的 goroutines 将被阻塞(因为 ch 是一个无缓冲的通道)。在此示例中,这无关紧要,但在 "real-life" 应用程序中,它会导致 goroutines 永远卡住(内存泄漏)。

如果您不想等待所有 foo() 调用完成并尽快 return(一旦遇到一个 true 值),一个选项是让 ch 缓冲,所以所有的 goroutines 都可以在它上面发送值而不会被阻塞。这样你就不需要接收(并因此等待)所有 foo() 调用来完成:

ch := make(chan bool, 10)
for i := 0; i < 10; i++ {
    go foo(i, ch)
}

flg := false
for i := 0; i < 10; i++ {
    if <-ch {
        flg = true
        break
    }
}

选择这种方法,您应该提供取消不再需要工作的 goroutine 的方法,以避免不必要的 CPU(和内存)使用。 context.Context is such a mean, read more about it here: .