go - 我应该如何向 gzip writer 添加缓冲?

标签 go gzip

我注意到 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/

相关文章:

go - 管道到执行过程

go - 如何使用索引构造翻转的单个位位域?

go - 如何将动态类型的数据写入结构中的字段

go - 使用结构成员而不是结构本身

go - 如何在运行时从 Go 代码获取 pod 外部 IP

java - 如何使用Java从.html.gz网页中提取内容?

asp.net - 在 Azure 网站上启用 gzip 压缩

postgresql - 在使用 psql 在本地下载/保存之前,在 AWS 实例上将表 gzip 转换为 csv

c++ - C++ 中的 ZLib 解压缩

php - GZIP 和 javascript