为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
米琪卡哇伊 2021-12-07 10:39:11
下面是 Go 编程书中的示例代码。我不明白为什么 close 需要是它自己的 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 回答

?
largeQ

TA贡献2039条经验 获得超7个赞

问题是它sizes不是一个 buffered chan,所以只有一个匿名 goroutines 可以在sizes需要读取之前实际完成。这会wg.Wait()导致永远等待(因为下一个 goroutine 正在阻塞sizes <-并且不能defer wg.Done())和死锁。


通过将 close 放入单独的 goroutine 中,它可以在sizes准备好时关闭chan,并sizes在两者之间进行处理。最终,这是 goroutine 的一个很好的用途——触发并忘记关闭!


为了让这段代码在没有更接近的 goroutine 的情况下工作,你可以简单地初始化sizes为一个缓冲的 chan,缓冲区 >= 的长度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与....是啊基本上你只是重新写在该点的整体功能。


查看完整回答
反对 回复 2021-12-07
  • 1 回答
  • 0 关注
  • 226 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信