2017-10-06 104 views
-2

我需要并行运行多个函数。
如果函数返回true(在通道上发送true),那么最终结果应该是true与golang中的通道卡住

如何使用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

“我如何使用频道实现此目标?” ---你有什么理由必须使用它的渠道? – zerkms

+1

请向我们展示您的尝试。你的代码根本不使用频道。 – Flimzy

+0

(同样,你最好使用'gofmt',因为你的代码不容易阅读) – Flimzy

回答

0

你只能从通道接收一个值(这将是由foo()调用一个发送的值,不可预知其中许多) ,但你想收到所有。

所以使用for循环,它收到你送(送)尽可能多的价值:

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

虽然在你的情况下,将接收到足够的循环,直到一个true值,因为这将确定flg的最终值,但仍建议接收所有其他值,其余的goroutine将被阻止(因为ch是无缓冲的通道)。在这个例子中它并不重要,但是在“真实生活”的应用程序中,它会导致goroutines永久停留(内存泄漏)。

如果你不想等待所有foo()调用来完成,(只要遇到一个true值)为尽快恢复,一个选项是让ch缓冲,因此所有够程可以在发送值它没有被阻挡。而你并不需要接受(因此等待)这种方式,所有的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 
    } 
} 

选择这种方法,你应该提供手段取消够程,其工作不再需要以避免不必要的CPU (和内存)使用情况。 context.Context是这样一个意思,在这里阅读更多关于它:Close multiple goroutine if an error occurs in one in go

1

您可能会开始从通道ch阅读和设置flgtrue一旦你得到真正的结果。就像这样:

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

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

定义它在全球范围内,从而每一个够程可以访问它:

var (
    wg sync.WaitGroup 
) 

然后在每次启动时的goroutine你添加一个够程等待组:

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

当够程结束它调用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