go - 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 完成时发生。关闭尺寸通道仍将允许循环读取所有已发送的消息/从通道,对吗?
解决方案
关闭尺寸通道仍将允许循环读取所有已发送的消息/从通道,对吗?
是的,但这不是问题。所有的 goroutine 都在等待从通道中读取(因此,没有人会写入它们)。sizes
因此,如果没有缓冲,该进程将死锁 。为了让工人完成,需要从中读取一些内容。为了wg.Wait()
完成,工人需要完成。
但是,在range sizes
close(sizes) 发生之前,无法完成(例如,找到一个空的、封闭的通道),直到工作人员完成(因为他们是写入大小的人)才能完成。
因此wg.Wait()
,close(sizes)
两者都必须在此同时发生之前完成range sizes
。
推荐阅读
- android - CallLog.Calls 中 TYPE 字段中的意外值
- c++ - 选择特定版本的 Visual Studio 命令行工具包并针对特定版本的 C++ 运行时环境编译文件
- regex - 提取 filname 并将名称存储在 csv 文件的新列中
- python - VS Code:python.exe 仅在从 Anaconda Navigator 打开时才能在终端中工作
- excel - 读取动态用户窗体复选框并填充数组
- asp.net - 400 对 ASP .NET Web API 文件流字符的错误请求
- vba - 允许在受保护的工作簿中分组/取消分组的 VBA 代码
- excel - 如何复制而不丢失信息?
- php - PHP $filename - 期望参数 1 是资源错误
- for-loop - Jekyll 是否会受到 Shopify 的 Liquid 规范声明的 50 项 for-loop 最大值的影响?