我想编写一个使用NET 3.5和GZipStream库进行多线程压缩/解压缩的程序。
输入文件非常大(假设数百GB)
我想在没有任何中间文件的情况下实现这一点。这是我最初的方法,但要求已经改变。
我正在考虑采用以下方法,并希望验证这在纸面上看起来是否合适:
从源文件中读取并将其拆分为内存中的常量大小。
跟踪线程数量,因为我们的内存有限。
每个块都通过单独的线程在内存中压缩。
这些压缩块按正确顺序推入队列。
有一个线程从队列中读取并将其连接到输出文件中。
还存储一些有关压缩块的元数据,这些元数据将在稍后放入标题中。我想用它来减压。
完成上述我对多线程解压缩的想法后就是:
读取有关连接块的元数据文件。
以元数据定义的块读取压缩文件中的数据。
每个块都由内存中的单独线程解压缩。
这些解压缩的块按正确的顺序添加到队列中。
有一个线程将解压缩的块连接成统一的输出文件。
以上看起来似乎有道理吗?
答案 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绑定。