我应该如何为gzip writer添加缓冲?

y0s*_*1an 7 gzip go

我注意到使用gzip包使用bufio内部读取gzip压缩的文件,但不写他们.我知道缓冲对于I/O性能很重要,那么缓冲gzip writer的正确方法是什么?

// 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)
Run Code Online (Sandbox Code Playgroud)

另外,在关闭它之前,我是否需要Flush()gzip writer或bufio writer(或两者),或者关闭它会自动刷新writer?

UPDATE:我现在明白了,这两个读取和写入使用gzip缓冲.所以缓冲a gzip.Writer真的是双缓冲.@peterSO认为这是多余的.@Steven Weinberg认为双缓冲可能减少系统调用的数量,但建议基准确定.

Ste*_*erg 5

使用 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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们使用 bufio 对 outFile 的写入进行分组,以避免不必要的系统调用。顺序是src -> gzip -> buffer -> file。

现在,当我们完成写入时,我们有多个需要关闭的缓冲区。我们需要告诉 gzip 我们已经完成,以便它可以刷新其缓冲区并将最终信息写入缓冲区。然后我们需要告诉 bufio.Writer 我们已经完成了,这样它就可以写出它为下一次批量写入而保存的内部缓冲区。最后,我们需要告诉操作系统我们已经完成了文件的处理。

这种销毁以与创建相反的顺序发生,因此我们可以使用 defers 使其更容易。在返回时,延迟以相反的顺序执行,所以我们知道我们正在以正确的顺序刷新,因为用于销毁的延迟就在用于创建的函数调用旁边。

  • @y0ssar1an:Steven 的示例是复制到 `io.Writer`:`gz := gzip.NewWriter(bufio.NewWriter(outFile))`。`gz` 是一个缓冲写入器。缓冲受缓冲区大小和数量的影响。双缓冲使用两个缓冲区来提供填充缓冲区和将另一个已满缓冲区写入设备之间的重叠。同时使用 `bufio` 和 `io.Copy` 是冗余缓冲。我们不需要使用两个缓冲方案。 (2认同)