duanbei1598 2016-01-15 19:52
浏览 35
已采纳

Sync.WaitGroup,为什么在goroutine中更近

Below is the example code in the Go programming book. I do not understand why the closer needs to be its own goroutine. I tried to move the closer into the main but it crashes. Somebody could explain why the closer needs to be in a separate goroutine?

Thanks!

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条回答 默认 最新

  • dongshi1188 2016-01-16 00:38
    关注

    The problem is that sizes is not a buffered chan, so only one of the anonymous goroutines can actually complete before sizes needs to be read from. That makes wg.Wait() wait forever (since the next goroutine is blocking on sizes <- and can't defer wg.Done()) and deadlocks.

    By throwing the closer in a separate goroutine, it can close the sizes chan whenever it's ready to do so, and process from sizes in between. Ultimately this is a great use of a goroutine -- fire and forget closing!

    To make this code work without the closer goroutine, you can simply initialize sizes as a buffered chan with a buffer >= the length of 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
    }
    

    However since filenames's length is unknowable at runtime, it's not possible to do this easily. You'd have to read through filenames, store it into a slice, then initialize sizes and for over range filenamesSlice and.... yeah basically you've just re-written the whole function at that point.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 划分vlan后不通了
  • ¥15 GDI处理通道视频时总是带有白色锯齿
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大
  • ¥15 使用EMD去噪处理RML2016数据集时候的原理
  • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大