我需要多次并行运行一个函数
如果函数返回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
}
答案 0 :(得分:2)
您可以从频道ch
开始阅读,并在获得真实结果后将flg
设置为true
。像这样:
//flg = flg || <- ch
for res := range ch {
if res {
flg = true
}
}
这种方式有效,但有一个严重的缺点 - for
循环无限地等待来自通道的新值。停止循环的惯用方法是关闭通道。你可以这样做:运行一个单独的goroutine,它会等到所有goroutines退出。 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 goroutine退出并关闭通道。 wg.Wait
阻止所有操作完成:
go func() {
wg.Wait()
close(ch)
}()
答案 1 :(得分:0)
您只能从频道收到一个值(这是foo()
个来电之一发送的值,不可预测的是其中之一),但您希望全部接收。
因此,使用for
循环来接收与您发送(发送)的值一样多的值:
for i := 0; i < 10; i++ {
flg = flg || <-ch
}
虽然在你的情况下循环就足够了,直到收到一个true
值,因为这将确定flg
的最终值,但仍然建议接收剩下的所有值。 goroutines将被阻止(因为ch
是一个无缓冲的通道)。在这个例子中没关系,但在“真实”应用程序中,它会导致goroutine永远停滞(内存泄漏)。
如果您不想等待所有foo()
次呼叫完成并尽快返回(只要遇到一个true
值),则可以选择{{1缓冲,所以所有goroutine都可以在其上发送值而不会被阻止。这样您就不需要接收(并因此等待)所有ch
次呼叫来完成:
foo()
选择这种方法,您应该提供取消不再需要工作的goroutine的方法,以避免不必要的CPU(和内存)使用。 context.Context
就是这样的意思,请在此处详细了解:Close multiple goroutine if an error occurs in one in go。