【问题标题】:How to use multiple threads for zlib compression如何使用多线程进行 zlib 压缩
【发布时间】:2015-05-18 03:42:03
【问题描述】:

我有大量数据(大约 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);

}

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

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

知道如何实现吗?

【问题讨论】:

  • 看起来您的代码每次调用 zlib_compress() 时只调用一次 deflate()。您是否在每个线程中多次调用 zlib_compress 函数?如果是这样,那么 deflateInit() 和 deflateEnd 不应该是 zlib_compress() 调用的一部分;相反,它们应该只在处理序列的开始和结束时完成(对于每个线程)
  • @JeremyFriesner 我已经删除了大部分代码以便于理解。是的,我目前只调用一次,但不是每个线程。我在压缩第一个数据块(512 kb)时调用 deflateInit(),在压缩最后一块数据(
  • @JeremyFriesner 非常感谢。您可以将其发布为答案吗?我愿意接受。
  • 好的,我已将我的 cmets 转换为答案。

标签: multithreading compression zlib


【解决方案1】:

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

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

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

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

==Chunk 1===
       -32K-====Chunk 2=======
                       --32K--====Chunk 3====

然后就可以合并压缩后的数据了。

【讨论】:

  • 不,您可以使用 n 个处理器/内核将压缩速度提高 n 倍。这就是pigz 所做的。每个线程都提供了要压缩的数据部分和该部分之前的 32K 未压缩数据。 32K 就是压缩上下文所需的全部。压缩后的流都可以并行生成,然后合并。
  • 请在 Mark Adler 的评论中工作(首选)或删除答案,因为它大部分是错误的!
  • 如果@MarkAdler 发表他的评论作为答案,我将删除我的答案;我不想试图解释他,但我也不想删除我的答案,因为他的评论附在上面。
【解决方案2】:

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

你预计会发生什么?

每个线程都需要它自己的z_stream 结构才能使用。两个线程同时访问同一个z_stream 是没有意义的。

【讨论】:

  • 我预计也会发生同样的情况。我提到这种方法只是为了解释我的意图。我想要一个替代方法来在两个多线程中压缩同一个文件。我认为这是不可能的传统方式,杰里米已经在 cmets 中证实了这一点。
  • 你问你真正想知道什么怎么样?如果您想知道如何加速多核压缩,请询问。杰里米回答的最后两段不正确。
  • 不,没有库版本。它使用 zlib,因此您可以查看 pigz 的源代码并使用相同的方法,或者根据您的需要调整 pigz 源代码。
  • 既然是大数据时代,如果把pigz提升为一个库,那么它会在大数据程序员中非常受欢迎。是否有任何隐藏的陷阱来防止这种情况发生?如果没有,我可以试一试。
  • 除了我的时间之外,唯一的障碍是界面。并行压缩库的用户对应用程序员如何使用它有什么期望?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-25
  • 2011-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多