Recursion 如何阻止(并加入)由未知数量的goroutine提供的通道?

Recursion 如何阻止(并加入)由未知数量的goroutine提供的通道?,recursion,go,channel,goroutine,Recursion,Go,Channel,Goroutine,我有一个递归函数。函数将根据所获得的数据使用各种不同的值来调用自己,因此递归的算术性和深度是未知的:每个调用可能会调用自己零次或多次。该函数可以返回任意数量的值 我想通过让goroutines和channels参与进来,将其并行化。内部的每个递归在其自己的goroutine中运行,并在通道上发回一个值。外部函数处理这些值 func outer(response []int) { results := make([]int) resultsChannel := make(chan int

我有一个递归函数。函数将根据所获得的数据使用各种不同的值来调用自己,因此递归的算术性和深度是未知的:每个调用可能会调用自己零次或多次。该函数可以返回任意数量的值

我想通过让goroutines和channels参与进来,将其并行化。
内部
的每个递归在其自己的goroutine中运行,并在通道上发回一个值。外部函数处理这些值

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
}
func外部(响应[]内部){
结果:=make([]int)
结果通道:=make(chan int)
内部:=func(…){

结果通道您可以使用
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何时完成

如果您正在读取某个频道的结果,那么当没有更多结果时,最明显的方法就是关闭该频道。您可以通过另一个goroutine来为我们完成此操作:

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

你现在应该可以通过
range
浏览
resultsChannel
来阅读所有的结果。

你是否可以寻找一个
sync.WaitGroup
?它的存在是最近向我指出的。很有可能。这看起来很有希望。@OldCurmudgeon医生说“请注意,具有正增量的呼叫必须在呼叫等待之前发生"。这意味着我肯定不能使用它?@Joe:这意味着
内部
在生成子goroutine之前应该调用
添加
。如果
外部
希望
内部
调用
完成
,那么你知道在调用之前该组仍然处于活动状态。对不起@JamesHenstridge我不太清楚你在说什么重复。第一次运行
internal
将运行,生成一个goroutine,继续,然后阻塞
for
循环,或者
Wait
。随后的递归将是异步的,因此如果我调用
Add
inside
internal
,它将被调用任意次数,包括调用
Wait
之后ed.另外,除非我遗漏了什么,否则我的整个问题是我无法调用
Done
,因为我不知道我的递归何时结束..谢谢。所以对
wg.Wait()
的调用发生在一些
wg.Add(1)
执行之前,对吗?文档说可以吗“请注意,具有正增量的调用必须在调用等待之前发生”,但我不知道这是否意味着“至少有一个要添加的调用”或“所有调用”。您能否谈谈为什么选择不使用
defer wg.Done()
?这不是建议的还是您的首选项?它似乎很适合这里,因为它不会过早退出。因为我们总是在调用
内部
之前调用
Add(1)
,我们知道等待组的计数器在函数体中总是为正值(至少在
完成
调用之前)。由于我们知道此处无法触发
等待
调用,因此可以安全地进一步增加计数器。如果让计数器提前瞬间达到零,则会出现争用条件(例如,将
添加(1)
调用移到
内部
)@OldCurmudgeon:在这里使用
defer
可能会更干净一些。但是对于没有提前返回的简单情况,这并没有什么区别。对于示例代码,按顺序显示调用似乎更简单。还有一个问题。我想轮询频道,并(例如)将结果添加到结果片段中(举例来说,我希望在存储结果之前对其进行过滤)。也可以说我的通道大小已被限制。如果我等到递归停止,那么我唯一的解决方案就是使用另一个goroutine来监视
结果通道