如何使用多线程进行 zlib 压缩

mk.*_*k.. 4 compression multithreading zlib

我有大量数据(大约 2 GB)需要使用 zlib (deflate()) 进行压缩。我目前正在一次读取 500 kb 的数据,将其压缩并将其写入我的输出文件。

使用 1 个线程,一切都很好。数据被压缩,我可以写它并解压缩它。

有 2 个线程时,进程挂在 deflate() 调用中。

这是我的 2 个 zlib comp 线程调用的函数的概要。

static z_stream z_str;

zlib_compress(...., bool last, bool first)
{

    if (first)
        deflateInit(&z_str, Z_DEFAULT_COMPRESSION);

    if (last)
        flush = Z_FINISH;
    else
        flush = Z_SYNC_FLUSH;

....
....
    status = deflate(&z_str, flush);
...
...
    if (last)
        deflateEnd(&z_str);

}
Run Code Online (Sandbox Code Playgroud)

据我了解,这两个调用在调用 deflate() 时都指的是同一个 zstream,这会导致不受欢迎的行为。

我试图将 z_str 作为局部变量并相应地修改代码。但是在解压缩时,它假设文件的总大小为 512,而这实际上只是第一个数据块。

知道如何实现这一目标吗?

Mar*_*ler 5

据我了解,这两个调用在调用 deflate() 时都引用相同的 zstream,这会导致不良行为。

您预计会发生什么?

每个线程都需要它自己的z_stream结构来工作。z_stream两个线程同时访问同一个线程是没有意义的。

  • 你可以问一下你真正想知道的事情吗?如果您想知道如何加快多核压缩速度,请询问。杰里米回答的最后两段不正确。 (2认同)

Jer*_*ner 5

可以有多个线程同时压缩数据,只要每个线程都有自己单独的 z_stream 对象。每个 z_stream 对象都应该调用 deflateInit(),然后根据需要调用尽可能多的 deflate(),然后在所有未压缩的数据传递给 deflate() 之后调用 deflateEnd()。使用这种技术,例如一次压缩两个不同的文件将是直接的。

但是我怀疑您正在尝试做的是加速单个大文件的压缩,不是吗?在那种情况下,您会发现这是不可能的,至少不是以明显的方式。不可能的原因是压缩流的后面字节取决于该流的前面字节的含义——这意味着在生成所有前面的字节之后才能生成它们,这排除了生成压缩文件的后半部分与前半部分并行。

您可以做的是生成两个单独的压缩文件;一个是未压缩文件前半部分的压缩内容,另一个是未压缩文件后半部分的压缩内容。这可以并行完成,因为两个压缩流将完全相互独立。请注意,您随后需要编写自己的例程来解压缩这两个文件并将结果再次连接回单个未压缩文件,因为标准压缩/解压缩实用程序不会意识到这种分而治之的技巧。

正如zlib (Adler) 的原作者所指出的,可以并行压缩大块数据,如pigz 中所示。本质上,您需要提供 32K 的未压缩数据处理特定块。

==Chunk 1===
       -32K-====Chunk 2=======
                       --32K--====Chunk 3====
Run Code Online (Sandbox Code Playgroud)

然后您可以合并压缩数据。

  • 不,您可以使用 _n_ 个处理器/内核将压缩速度提高 _n_ 倍。这就是 [pigz](http://zlib.net/pigz/) 所做的。每个线程都提供了要压缩的数据部分和该部分之前的 32K 未压缩数据。32K 是压缩上下文所需的全部。压缩的流都可以并行生成然后组合。 (5认同)