我注意到 gzip 包 uses bufio
internally用于读取 gzip 文件,但不用于写入它们。我知道缓冲对于 I/O 性能很重要,那么缓冲 gzip 编写器的正确方法是什么?
// ignoring error handling for this example
outFile, _ := os.Create("output.gz")
// Alternative 1 - bufio.Writer wraps gzip.Writer
gzipWriter, _ := gzip.NewWriter(outFile)
writer, _ := bufio.NewWriter(gzipWriter)
// Alternative 2 - gzip.Writer wraps bufio.Writer
writer, _ := bufio.NewWriter(outFile)
gzipWriter, _ := gzip.NewWriter(writer)
// Alternative 3 - replace bufio with bytes.Buffer
buf := bytes.NewBuffer()
gzipWriter, _ := gzip.NewWriter(&buf)
此外,我是否需要在关闭 gzip 编写器或 bufio 编写器(或两者)之前对它进行 Flush(),还是关闭它会自动刷新编写器?
更新:我现在了解到, 读取和写入都使用 gzip 进行缓冲。所以缓冲 gzip.Writer
实际上是双重缓冲。 @peterSO 认为这是多余的。 @Steven Weinberg 认为双缓冲可能会减少系统调用的数量,但建议进行基准测试以确保。
最佳答案
使用 bufio 的正确方法是为每次调用 write 包装一个高开销的 writer。任何需要系统调用的编写器都是这种情况。在这种情况下,您的“outFile”是一个操作系统文件,每次写入都是一个系统调用。
outFile, err := os.Create("output.gz")
defer outFile.Close()
buf := bufio.NewWriter(outFile)
defer buf.Flush()
gz := gzip.NewWriter(buf)
defer gz.Close()
io.Copy(gz, src)
return
在这种情况下,我们将对 outFile 的写入与 bufio 分组,以避免不必要的系统调用。顺序是 src -> gzip -> buffer -> file.
现在,当我们完成写入时,我们有多个缓冲区需要关闭。我们需要告诉 gzip 我们已经完成,以便它可以刷新缓冲区并将最终信息写入缓冲区。 然后我们需要告诉 bufio.Writer 我们已经完成了,这样它就可以写出它为下一批写入保存的内部缓冲区。最后,我们需要告诉操作系统我们已处理完该文件。
这种销毁以与创建相反的顺序发生,因此我们可以使用 defer 使其更容易。返回时,延迟以相反的顺序执行,因此我们知道我们正在以正确的顺序刷新,因为用于销毁的延迟紧挨着用于创建的函数调用。
关于go - 我应该如何向 gzip writer 添加缓冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25171385/