为什么 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
?
我觉得是编词典的频率不同。
这是速度和压缩效率之间的平衡,例如 gzip 与 lzma。
我猜它在拆分案例中更常见。
所以字典的数字比较类似下面
在 YouTube、Raul Fraile: How GZIP compression works | JSConf EU 2014 上有一个 20 分钟的讲座。
原因是对于这个特殊的、相当不寻常的输入,较小的放气块比较大的放气块更好。默认情况下 gzip
使用较大的放气块,因为这最适合普通输入数据。 parallel
命令通过每 1 MB 分解输入来强制几个较小的放气块,从而产生较小的增益。尽管大多数块的大小仍然相同。
您可以通过使用 deflateInit2()
中的 zlib 的 memLevel
参数为 每个 块设置较小的块大小来做得更好.在这里,我每次都在一个线程中压缩相同的输出,使用从 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
相差不远。
文件位于:"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
?
我觉得是编词典的频率不同。 这是速度和压缩效率之间的平衡,例如 gzip 与 lzma。
我猜它在拆分案例中更常见。 所以字典的数字比较类似下面
在 YouTube、Raul Fraile: How GZIP compression works | JSConf EU 2014 上有一个 20 分钟的讲座。
原因是对于这个特殊的、相当不寻常的输入,较小的放气块比较大的放气块更好。默认情况下 gzip
使用较大的放气块,因为这最适合普通输入数据。 parallel
命令通过每 1 MB 分解输入来强制几个较小的放气块,从而产生较小的增益。尽管大多数块的大小仍然相同。
您可以通过使用 deflateInit2()
中的 zlib 的 memLevel
参数为 每个 块设置较小的块大小来做得更好.在这里,我每次都在一个线程中压缩相同的输出,使用从 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
相差不远。