我有一个无缓冲的通道,i
工作量从(文件系统路径)获取值并处理它(通过HTTP发送文件内容)。当我增加i
时,我遇到了问题。
当我运行时:
paths := make(chan string)
for i := 0; i < 5; i++ {
go func() {
for path := range paths {
fmt.Println(path)
}
}()
}
walkFn := func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
paths <- path
}
return nil
}
filepath.Walk("/tmp/foo", walkFn)
close(paths)
它可以预期运行并输出/tmp/foo
的所有内容:
/tmp/foo/2
/tmp/foo/file9
/tmp/foo/file91
/tmp/foo/file90
/tmp/foo/file900
/tmp/foo/file901
/tmp/foo/file902
/tmp/foo/file92
/tmp/foo/file97
/tmp/foo/file93
/tmp/foo/file94
/tmp/foo/file95
/tmp/foo/file96
/tmp/foo/file98
/tmp/foo/file99
但是当我通过HTTP发送文件内容时,受影响文件的数量突然下降:
for i := 0; i < 5; i++ {
go func() {
for path := range paths {
resp, err := http.Head("https://example.com/" + strings.TrimPrefix(path, rootDir+"/"))
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
fmt.Printf("%s: %s\n", path, resp.Status)
}
}()
}
受影响的文件数量从15减少(这是目录中存在的数量),直到10:
/tmp/foo/2: 404 Not Found
/tmp/foo/file901: 404 Not Found
/tmp/foo/file900: 404 Not Found
/tmp/foo/file9: 404 Not Found
/tmp/foo/file90: 404 Not Found
/tmp/foo/file902: 404 Not Found
/tmp/foo/file91: 404 Not Found
/tmp/foo/file92: 404 Not Found
/tmp/foo/file93: 404 Not Found
/tmp/foo/file94: 404 Not Found
这是一个表格,它将i
的值与输出行数相关联:
+-----+-------+
| `i` | lines |
+-----+-------+
| 1 | 15 |
| 5 | 10 |
| 6 | 9 |
| 15 | 0 |
+-----+-------+
为什么会发生这种情况?如何同时处理所有频道条目?这是http
请求的问题吗?
答案 0 :(得分:1)
问题是在这一行之后:
filepath.Walk("/tmp/foo", walkFn)
所有路径都是通过paths
频道发送的,这意味着有人收到了这些路径。但是,这并不意味着接收goroutine的人已经完全完成了。
因此,当你的程序在close(paths)
之后退出时,仍有goroutines正在运行,因为main
已完成而被杀死。
https://golang.org/ref/spec#Program_execution
程序执行从初始化主包然后调用main函数开始。当该函数调用返回时,程序退出。 它不会等待其他(非主要)goroutines完成。
一个简单的解决方案是添加
select{}
在您的计划结束时。这将使它永远阻止。