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

我想通过涉及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/

10-16 23:27