为什么 gnu 并行分块会提高 gzip 的压缩大小?

Why would gnu parallel chunking improve gzip's compression size?

文件位于:"Unexpected Efficiency Dept."

前9000万个数字约占761MB,输出为:

 seq 90000000

根据 man parallel,它可以通过切碎输入并使用不同的 CPU 来压缩块来加快 gzip 归档大文件的速度。所以即使 gzip 单线程 这个技术使它成为 多线程 :

seq 90000000  | parallel --pipe --recend '' -k gzip -9 >bigfile.gz

在 Intel Core i3-2330M (4) @ 2.2GHz 上用了 46 秒。

通过管道传输到普通的旧 gzip:

seq 90000000  | gzip -9 > bigfile2.gz

用了 80 秒,同样 CPU。现在是惊喜:

ls -log bigfile*.gz

输出:

-rw-rw-r-- 1 200016306 Jul  3 17:27 bigfile.gz
-rw-rw-r-- 1 200381681 Jul  3 17:30 bigfile2.gz

300K 更大?那看起来不对劲。首先,我检查了 zdiff 文件是否具有相同的内容——是的,相同。我原以为 any 压缩器在处理连续数据流时会比分块压缩器做得更好。为什么 bigfile2.gz 不小于 bigfile.gz

我觉得是编词典的频率不同。 这是速度和压缩效率之间的平衡,例如 gziplzma

我猜它在拆分案例中更常见。 所以字典的数字比较类似下面

YouTubeRaul Fraile: How GZIP compression works | JSConf EU 2014 上有一个 20 分钟的讲座。

原因是对于这个特殊的、相当不寻常的输入,较小的放气块比较大的放气块更好。默认情况下 gzip 使用较大的放气块,因为这最适合普通输入数据。 parallel 命令通过每 1 MB 分解输入来强制几个较小的放气块,从而产生较小的增益。尽管大多数块的大小仍然相同。

您可以通过使用 deflateInit2() 中的 zlibmemLevel 参数为 每个 块设置较小的块大小来做得更好.在这里,我每次都在一个线程中压缩相同的输出,使用从 9 到 2 的 memLevel 值,其中较小的 memLevel 是较小的放气块大小(请注意 zlib 比你的 gzip 在默认级别):

  • 9 - 199688429
  • 8 - 198554111(默认)
  • 7 - 191582070
  • 6 - 184880482
  • 5 - 181295029
  • 4 - 180137425(此输入的最佳值)
  • 3 - 181176610
  • 2 - 185759115

此数据的最佳 memLevel 结果为 4,压缩数据比默认 memLevel 8 小 12 MB (9%)。对于 memLevel 8,deflate 块大小为 16383 个符号,而对于 memLevel 4,deflate 块大小为 1023 个符号。一个符号是文字字节或匹配项。

改进来自输入的极其规则的性质,导致匹配和文字命令的规则序列。块大小越小,出现的这种不同的命令就越少,然后需要更少的比特来对它们中的每一个进行编码。 memLevel 3 仍然如此,但到那时每个 deflate 块开头的代码描述的开销抵消了较少不同代码的改进。

zopfli is a deflate compressor that optimizes the block size and the commands selected, and managed to compress it to 100,656,812 bytes. It took three and a half hours though! zopfli is invoked with pigz 使用压缩级别 11。

效果可能是由于压缩块大小。使用一系列设置压缩相同的输入流:

for i in {1..9}; do seq 90000000 | gzip -$i >$i.gz; done

给出在 gzip -5:

时达到最小值的文件大小
-rw-r--r-- 1 203473375 Jul  4 16:39 1.gz
-rw-r--r-- 1 201160853 Jul  4 16:40 2.gz
-rw-r--r-- 1 200181562 Jul  4 16:40 3.gz
-rw-r--r-- 1 204266147 Jul  4 16:40 4.gz
-rw-r--r-- 1 199144028 Jul  4 16:40 5.gz
-rw-r--r-- 1 199688429 Jul  4 16:40 6.gz
-rw-r--r-- 1 199689546 Jul  4 16:41 7.gz
-rw-r--r-- 1 200376213 Jul  4 16:41 8.gz
-rw-r--r-- 1 200381681 Jul  4 16:42 9.gz

这与 gzip 的默认值 -6 相差不远。