在golang中遇到频道

时间:2017-10-06 09:36:39

标签: go channel goroutine

我需要多次并行运行一个函数 如果函数返回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
}

2 个答案:

答案 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)
}()

所有在一起:https://play.golang.org/p/8qiuA29-jv

答案 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