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

agc*_*agc 8 linux shell gzip chunking gnu-parallel

档案下:"意外效率部门"

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

 seq 90000000
Run Code Online (Sandbox Code Playgroud)

根据man parallel它,它可以gzip通过切断输入并使用不同的CPU来压缩块来加速归档大文件.因此即使gzip单线程,这种技术也使它成为多线程:

seq 90000000  | parallel --pipe --recend '' -k gzip -9 >bigfile.gz
Run Code Online (Sandbox Code Playgroud)

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

管道到老了gzip:

seq 90000000  | gzip -9 > bigfile2.gz
Run Code Online (Sandbox Code Playgroud)

在相同的CPU上花了80秒.现在出人意料:

ls -log bigfile*.gz
Run Code Online (Sandbox Code Playgroud)

输出:

-rw-rw-r-- 1 200016306 Jul  3 17:27 bigfile.gz
-rw-rw-r-- 1 200381681 Jul  3 17:30 bigfile2.gz
Run Code Online (Sandbox Code Playgroud)

300K更大?这看起来不对.首先,我检查zdiff文件是否具有相同的内容 - 是的,相同.我认为任何压缩器在连续数据流方面都会比分块数据流做得更好.为什么不bigfile2.gz小于bigfile.gz

Mar*_*ler 8

原因在于,对于这种特殊的,相当不寻常的输入,较小的放气块优于较大的放气块.默认情况下gzip使用较大的deflate块,因为这对正常输入数据最有效.该parallel命令通过每1 MB分解输入强制一些较小的放气块,从而产生较小的增益.虽然大多数块仍然是相同的大小.

通过使用zlib的参数为每个块设置较小的块大小,可以做得更好.在这里,我每次在单个线程中压缩相同的输出,使用从9到2的值,其中较小的是较小的deflate块大小(请注意,zlib比默认级别的稍微好一点):memLeveldeflateInit2()memLevelmemLevelgzip

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

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

改进来自输入的极其规则性,导致匹配和文字命令的常规序列.块大小越小,出现的这些不同命令就越少,然后需要更少的位来对每个命令进行编码.对于memLevel3 来说仍然如此,但到那时,每个deflate块开始处的代码描述的开销取消了较少的不同代码的改进.

zopfli是一个deflate压缩器,它优化块大小和所选命令,并设法将其压缩到100,656,812字节.虽然花了三个半小时!使用压缩级别11 zopfli调用pigz.