我有一个递归函数。该函数将根据获得的数据使用各种不同的值进行调用,因此递归的深度和深度是未知的:每次调用可能会调用自身零次或多次。该函数可以返回任意数量的值。
我想通过涉及goroutine和 channel 来使其并行化。 inner
的每次递归都在其自己的goroutine中运行,并在 channel 上发送回一个值。外部函数处理这些值。
func outer(response []int) {
results := make([]int)
resultsChannel := make(chan int)
inner := func(...) {
resultsChannel <- «some result»;
// Recurse in a new goroutine.
for _, recursionArgument in «some calculated data» {
go inner(recursionArgument)
}
}
go inner(«initial values»);
for {
result := <- resultsChannel
results = append(results, result)
// HELP! How do I decide when to break?
}
return results
}
问题在于转义结果 channel 循环。由于递归的“形状”(未知的深度和深度),我无法说“n个事件后完成”,也无法发送哨兵值。
如何检测所有递归何时发生并从
outer
返回?有没有更好的方法来解决这个问题? 最佳答案
您可以使用sync.WaitGroup
来管理所生成的goroutine的集合:在生成每个新goroutine之前调用Add(1)
,并在每个goroutine完成后调用Done
。所以像这样:
var wg sync.WaitGroup
inner := func(...) {
...
// Recurse in a new goroutine.
for _, recursionArgument := range «some calculated data» {
wg.Add(1)
go inner(recursionArgument)
}
...
wg.Done()
}
wg.Add(1)
go inner(«initial values»)
现在,等待
wg
会告诉您所有goroutine完成时。如果您正在从某个 channel 读取结果,则可以通过关闭该 channel 来判断何时没有更多结果。您可以通过另一个goroutine为我们做到这一点:
go func() {
wg.Wait()
close(resultsChannel)
}()
现在,您应该能够简单地将
range
替换为resultsChannel
来读取所有结果。关于recursion - 如何在数量众多的goroutine提供的 channel 上阻止(并加入)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20350915/