如何使用GZipStream进行多线程压缩/解压缩,而无需在非常大的输入上使用中间文件

时间:2018-05-08 13:17:30

标签: c# multithreading stream compression gzipstream

  • 我想编写一个使用NET 3.5和GZipStream库进行多线程压缩/解压缩的程序。

  • 输入文件非常大(假设数百GB)

  • 我想在没有任何中间文件的情况下实现这一点。这是我最初的方法,但要求已经改变。

我正在考虑采用以下方法,并希望验证这在纸面上看起来是否合适:

  1. 从源文件中读取并将其拆分为内存中的常量大小。

  2. 跟踪线程数量,因为我们的内存有限。

  3. 每个块都通过单独的线程在内存中压缩。

  4. 这些压缩块按正确顺序推入队列。

  5. 有一个线程从队列中读取并将其连接到输出文件中。

  6. 还存储一些有关压缩块的元数据,这些元数据将在稍后放入标题中。我想用它来减压。

  7. 完成上述我对多线程解压缩的想法后就是:

    1. 读取有关连接块的元数据文件。

    2. 以元数据定义的块读取压缩文件中的数据。

    3. 每个块都由内存中的单独线程解压缩。

    4. 这些解压缩的块按正确的顺序添加到队列中。

    5. 有一个线程将解压缩的块连接成统一的输出文件。

    6. 以上看起来似乎有道理吗?

3 个答案:

答案 0 :(得分:1)

我不认为GZip可以这样分解。整个流在开始时依赖于一些令牌字典(Huffman tree或变体)。作为提示,GZipStream.CanSeek()始终返回false。

所以你的观点3.会失败 - 这些不是独立的。

可能有效的是并行处理2个甚至3个文件,具体取决于您的I / O硬件。更适合快速SSD而不是旧硬盘。网络I / O通常被认为是慢速HDD。

答案 1 :(得分:1)

是的,当你将每个块视为一个独立的项目(它获得它自己的GZip流)时,这应该工作。但它会增加一些开销,你的整体压缩会略低一些。

对于每个块,您需要大小和序列号来反序列化和重新排序 无论如何,接收器必须重新排序,因此您可以跳过发送方。

但是很难估计你会获得多少,压缩有点CPU密集,但仍然比大多数I / O设备快得多。

答案 2 :(得分:1)

当然,这样可以正常工作。碰巧的是,有效gzip文件的串联也是一个有效的gzip文件。每个不同的可解压缩流称为gzip成员。您的元数据只需要文件中的偏移量来开始每个流。

gzip标头的额外块限制为64K字节,因此这可能会限制块的大小,例如,大约几十到一百兆。出于另一个原因,我建议你要压缩的数据块至少为几兆字节 - 以避免降低压缩效率。

连接的缺点是你没有全面检查输入的完整性。例如,如果你以某种方式弄乱了成员的顺序,那么在解压缩时就不会检测到这一点,因为无论顺序如何,每个成员的完整性检查都会通过。因此,您可能希望包含对未压缩数据的整体检查。一个例子是整个未压缩数据的CRC,可以使用zlib的crc32_combine()从成员的CRC中计算出来。

我很想知道在你的情况下你是否能从并行减压中获得显着的加速。解压缩通常足够快,以便在读取的大容量存储设备上进行I / O绑定。