首页 > 解决方案 > Goroutine 示例 - Donovan/Kernighan 的书 - 需要解释

问题描述

以下示例取自 Donovan/Kernighan 的书中:

func makeThumbnails6(filenames <-chan string) int64 {
    sizes := make(chan int64)
    var wg sync.WaitGroup // number of working goroutines
    for f := range filenames {
        wg.Add(1)
        // worker
        go func(f string) {
            defer wg.Done()
            thumb, err := thumbnail.ImageFile(f)
            if err != nil {
                log.Println(err)
                return
            }
            info, _ := os.Stat(thumb) // OK to ignore error
            sizes <- info.Size()
        }(f)
    }
    // closer
    go func() {
        wg.Wait()
        close(sizes)
    }()
    var total int64
    for size := range sizes {
        total += size
    }
    return total
}

书中说:

“这两个操作,等待和关闭,必须与循环大小并发。考虑替代方案:如果等待操作被放置在循环之前的主 goroutine 中,它永远不会结束”

这是我不明白的 - 如果它们没有放在单独的 goroutine 中,那么wg.Wait将阻塞主 goroutine,所以close(sizes)会在所有其他 goroutine 完成时发生。关闭尺寸通道仍将允许循环读取所有已发送的消息/从通道,对吗?

标签: gogoroutine

解决方案


关闭尺寸通道仍将允许循环读取所有已发送的消息/从通道,对吗?

是的,但这不是问题。所有的 goroutine 都在等待从通道中读取(因此,没有人会写入它们)。sizes因此,如果没有缓冲,该进程将死锁 。为了让工人完成,需要从中读取一些内容。为了wg.Wait()完成,工人需要完成。

但是,在range sizesclose(sizes) 发生之前,无法完成(例如,找到一个空的、封闭的通道),直到工作人员完成(因为他们是写入大小的人)才能完成。

因此wg.Wait()close(sizes)两者都必须在此同时发生之前完成range sizes


推荐阅读