我正在使用Go更深入地研究并发性。我正在阅读的一本书给出了以下示例,它基本上压缩了命令行参数中的文件。
package main
import (
"compress/gzip"
"io"
"os"
)
func main() {
for _, file := range os.Args[1:] {
compress(file)
}
}
func compress(filename string) error {
in, err := os.Open(filename)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(filename + ".gz")
if err != nil {
return err
}
defer out.Close()
gzout := gzip.NewWriter(out)
_, err = io.Copy(gzout, in)
gzout.Close()
return err
}
这本书然后解释说,如果你想处理几百个文件,保持这样的肯定会比你使用goroutine慢,所以对main()
函数进行了以下修改使用它们:
var wg sync.WaitGroup
var i int = -1
var file string
for i, file = range os.Args[1:] {
wg.Add(1)
go func(filename string) {
compress(filename)
wg.Done()
}(file)
}
wg.Wait()
fmt.Printf("Compressed %d files\n", i+1)
然后注意到关于内联函数定义及其参数(文件名)的“技巧”是必要的“因为我们在for循环中执行goroutine”。
我想我不明白为什么需要上面的内联函数来实现这个功能,不能使用以下内容,或者我错过了一个技巧?
for i, file = range os.Args[1:] {
wg.Add(1)
go compress(file)
wg.Done()
}
wg.Wait()
fmt.Printf("Compressed %d files\n", i+1)
答案 0 :(得分:4)
如果您只是执行:
compress(file)
在同一个goroutine中执行,所以在调用完成之前,你不会做任何其他事情。
因此,如果您想并行处理,则需要使用go
关键字启动新的goroutine。
如果你这样做:
go compress(file)
然后它将启动一个新的goroutine来压缩每个文件。
但是,只要main
函数启动所有goroutine,它就会结束执行(它不会等待所有goroutine完成)。
这就是为什么他们包含了wg
来电。
由于compress
函数没有收到WaitGroup
来调用Done
,因此他们实现了内联函数,以便在goroutine结束后立即调用wg.Done()
对该文件的压缩。
原因如下:
go func(filename string) {
compress(filename)
wg.Done()
}(file)