Sync.WaitGroup,为什么更接近goroutine

时间:2016-01-15 19:52:12

标签: go goroutine

以下是Go编程手册中的示例代码。我不明白为什么更接近需要成为它自己的goroutine。我试图将更接近移动到主要部分,但它崩溃了。有人可以解释为什么更接近需要在一个单独的goroutine?

谢谢!

func makeThumbnails(filenames <-chan string, result chan<- int64) int64 {
  sizes := make(chan int64)
  var wg sync.WaitGroup
  for f := range filenames {
      wg.Add(1)
      go func(f string) {
        defer wg.Done()
        sizes <- int64(len(f))
      }(f)
  }

  // **closer**, why this guy needs to be in a goroutine???
  go func() {
    wg.Wait()
    close(sizes)
  }()

  var total int64
  for size := range sizes {
    total += size
  }
  result <- total
  return total
}

1 个答案:

答案 0 :(得分:4)

问题是sizes不是缓冲的chan,因此在需要读取sizes之前,只有一个匿名goroutine可以实际完成。这使得wg.Wait()永远等待(因为下一个goroutine在sizes <-上阻止,并且可以defer wg.Done())和死锁。

通过将近距离投射到一个单独的goroutine中,只要它准备好就可以关闭sizes chan,然后在sizes之间进行处理。最终,这是一个伟大的使用goroutine - 火和忘记关闭!

要使此代码在没有更接近goroutine的情况下工作,您只需将sizes初始化为缓冲的chan,其缓冲区为&gt; = filenames的长度。

func makeThumbnails(filenames <-chan string, result chan<- int64) int64 {
    sizes := make(chan int64, 10) // buffered channel, now!
    // if filenames sends more than 10 strings, though, we're in trouble!!

    var wg sync.WaitGroup
    for f := range filenames {
        wg.Add(1)
        go func(f string) {
            defer wg.Done()
            sizes <- int64(len(f))
        }(f)
    }

    // **closer**, this guy doesn't need to be a goroutine!!
    wg.Wait()
    close(sizes)

    var total int64
    for size := range sizes {
        total += size
    }
    result <- total
    return total
}

但是,由于filenames的长度在运行时是不可知的,因此无法轻松完成此操作。您必须仔细阅读filenames,将其存储到切片中,然后初始化尺寸并for超过range filenamesSlice和....是的,基本上您只是重新开始 - 写完整个功能。