Zstd: 如果压缩上下文被定期丢弃,则压缩率更高

创建于 2019-07-08  ·  3评论  ·  资料来源: facebook/zstd

如果不重新使用压缩上下文,我的压缩率将始终略有提高。
我正在创建ZSTD压缩上下文,然后在一个调用ZSTD_compressCCtx的循环中,每次提供1MB的数据缓冲区。 在过程结束时,释放压缩上下文。
如果我先释放压缩上下文并创建新的压缩上下文,然后再继续压缩下一个1MB缓冲区,则输出文件的大小始终要小1%左右。
另一个有趣的事实是,与2 MB的输入缓冲区相比,如果我将2MB的输入缓冲区与数据一起使用,则压缩率大约提高1-1.5%。
在我的用例中,我不受内存资源的限制。
问题)

  • 在压缩大块数据之间放弃压缩上下文是否是更好的做法?

    • 建议的最佳输入缓冲区大小是什么(即减小缓冲区大小将降低压缩率,而增大缓冲区大小将不会改善压缩率)?

    • 任何告诉zstd“使用所需的内存,但给我更好的压缩率和/或速度”的方法

    • 真正具有上下文上下文的流式压缩是否仅对内存受限的用例有利? 如果我有足够的内存,最好独立压缩大型(> 1MB)缓冲区吗?

question

所有3条评论

@scherepanov

这个结果令人惊讶。
使用ZSTD_compressCCtx() ,在相同的输入和相同的压缩级别下,(从压缩率的角度来看)是否重新使用上下文都无关紧要。 重用上下文的唯一影响就是节省分配和初始化时间,仅此而已。 如果它影响压缩率,那就很奇怪了,而且可能是错误的。

如果可能的话,我想重现这种情况。 您正在使用哪个版本?

在压缩大块数据之间放弃压缩上下文是否是更好的做法?

您永远不需要丢弃上下文。
唯一的“好的”理由是简化代码。
但是从性能角度来看,这应该只是有益的,没有缺点。

推荐的最佳输入缓冲区大小

这是高度情况。 没有“通用”阈值。
一般而言,超过8倍的窗口大小,增加块大小的价值越来越小。
但是,窗口大小是一个动态值,具体取决于压缩级别。
它的大小从512 KB(1级)到8 MB(19级)不等。

任何告诉zstd“使用所需的内存,但给我更好的压缩率”的方法

19级应该是这种类型

和/或速度”

级别4通常是这种类型:压缩速度非常快,但使用的内存量过大。 那是我能想到的最接近的。

真正具有上下文上下文的流式压缩是否仅对内存受限的用例有利? 如果我有足够的内存,最好独立压缩大型(> 1MB)缓冲区吗?

一次压缩/解压缩独立块( ZSTD_compressCCtx()ZSTD_decompressDCtx() )只是简单得多,而且可能会尽可能高效。 如果可以做到,那就更好了。 流模式在此之上增加了很多复杂性。 复杂性主要是内部的和隐藏的,但主要思想是,它不能比简单的单遍压缩或解压缩更好/更快。

感谢您非常明确的回答。
我追踪到不同的压缩率来对数据进行不同的排序。 是的,正如您所说的,重用上下文与丢弃并没有什么区别。 抱歉,在提出问题之前,我应该更加小心并进行更多调查。
您的评论很清楚,也很解释。 我认为确实需要将其添加到文档中。 特别是关于流与非流的区别的一部分-我一直认为流更有效,因为您可以更好地构建字典(尽管不清楚当文件中的数据发生变化时如何修改字典)。 清楚了解流与“基于块”的压缩几乎相同非常重要。 另一方面,由于您可以自动处理块大小,因此流式传输可能更有效。 我使用默认压缩级别3的1MB块大小,似乎不足以获得更好的压缩。 从这个角度来看,流传输可以提高压缩率,因为您可以更优化地确定块大小。 (这样对吗???)

流与“基于块”的压缩几乎相同

它不完全相同。

如果将输入数据切成块,然后将它们独立地传递给ZSTD_compressCCtx() ,那么最终将得到多个独立的压缩块。 每个压缩块都是一个独立的_frame_。 它们可以以任何顺序解压缩,因为每个帧都是独立的。

如果使用ZSTD_compressStream()将相同的数据发送到单个流中而没有分块,则最终会得到_single frame_。 在内部,框架被切成块,是的,但这并不重要,因为块不是独立的。 要解码帧的任何部分,必须从头开始解码所有内容。

从理论上讲,单个帧应比多个独立帧更好地压缩。 那是因为将数据分割成多个独立的块会使其在每个块的开头失去一些压缩机会。
但是,快速模式只是“概率”压缩器,为了快速运行,它们匆忙下注。 并非所有机会都是平等的,有时选择一个机会只是掩盖了以后的更好机会。 这是非常特定于数据的。
因此,在极少数情况下,将数据分割成独立的块可能会与单个流竞争,最终会发生这种情况。
但是我不会打赌。 在大多数情况下,即使很少,单流也应该获胜。

此页面是否有帮助?
0 / 5 - 0 等级