1

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

我想通过涉及 goroutine 和通道来并行化它。每个递归都inner在自己的 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
}

问题在于逃避结果通道循环。由于递归的“形状”(未知的数量和深度),我不能说“在n 个事件后完成”,也不能发送哨兵值。

我如何检测我的所有递归何时发生并从返回outer?有没有更好的方法来解决这个问题?

4

1 回答 1

3

您可以使用 async.WaitGroup来管理您生成的 goroutine 的集合:在生成Add(1)每个新的 goroutine 之前以及Done每个 goroutine 完成时调用。所以是这样的:

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

您现在应该能够简单rangeresultsChannel阅读所有结果。

于 2013-12-03T14:53:14.650 回答