C++ C++/C多线程同时读取gz文件

C++ C++/C多线程同时读取gz文件,c++,multithreading,zlib,compression,deflate,C++,Multithreading,Zlib,Compression,Deflate,我正在尝试从多个线程读取gzip压缩文件 我认为这将大大加快解压过程,因为多个线程中的gzread函数从不同的文件偏移量开始(使用gseek),因此它们读取文件的不同部分 简化的代码如下 // in threads auto gf = gzopen("file.gz",xxx); gzseek(gf,offset); gzread(xx); gzclose(gf); 令我惊讶的是,我的多线程版本程序根本没有加速。20线程版本使用的时间与单线程版本完全相同。我敢肯定这离磁盘瓶颈还很远 我想zli

我正在尝试从多个线程读取gzip压缩文件

我认为这将大大加快解压过程,因为多个线程中的
gzread
函数从不同的文件偏移量开始(使用
gseek
),因此它们读取文件的不同部分

简化的代码如下

// in threads
auto gf = gzopen("file.gz",xxx);
gzseek(gf,offset);
gzread(xx);
gzclose(gf);
令我惊讶的是,我的多线程版本程序根本没有加速。20线程版本使用的时间与单线程版本完全相同。我敢肯定这离磁盘瓶颈还很远

我想zlib膨胀功能可能需要解压整个文件,以便读取哪怕是一小部分,但我未能从他们的手册中获得任何线索


有人知道如何在我的例子中加速吗?

zlib实现没有多线程(“zlib是线程安全的吗?-是的……当然,一次只能从一个线程对任何给定的zlib或gzip流进行操作。”)并将“整个文件”解压缩到所需位置

zlib格式具有错误对齐(位对齐)/无偏移字段()以启用并行解压缩/查找

例如,您可以尝试z(deflate/inflate)的另一种实现(或者从单核时代的古老压缩转换为非zlib现代并行格式,从谷歌的xz/lzma/something)

pigz代表gzip的并行实现,是gzip的全功能替代品,它在压缩数据时充分利用了多处理器和多核。pigz由MarkAdler编写,使用zlib和pthread库。要编译和使用pigz,请阅读源代码发行版中的自述文件。你可以看报纸

手册页是,它有有用的信息

它使用与zlib兼容的格式,但采用并行压缩:

每个部分原始放气流由一个空存储块终止。。。以在字节边界处结束该部分位流

尽管如此,DEFLATE格式对于并行解压缩还是不好的:

解压不能并行化,至少在没有为此目的专门准备的放气流的情况下是不行的。因此,pigz使用单个线程(主线程)进行解压缩,但将创建另外三个线程用于读取、写入和校验计算,这在某些情况下可以加快解压缩速度


tl;dr:zlib不是为随机访问而设计的,虽然构建索引需要完整的通读,但在您的情况下可能没有帮助

让我们调查一下这个问题。是一个包装器,包含:

/* if within raw area while reading, just go there */
if (state->mode == GZ_READ && state->how == COPY &&
        state->x.pos + offset >= 0) {
如果我们正在处理gzip文件,“在原始区域内”听起来不太正确。让我们在以下内容中查找
state->how
的含义:

对。在
gz_open
的末尾,调用
gz_reset
how
设置为0。回到
gzseek64
,我们最终对状态进行了以下修改:

state->seek = 1;
state->skip = offset;
,调用时,通过调用来处理此操作:


沿着这个兔子洞再往前走一点,我们发现
gz_skip
调用
gz_fetch
,直到
gz_fetch
为所需的搜索处理了足够的输入
gz_fetch
在其第一次循环迭代中,调用
gz_look
,设置
state->how=GZIP
,这将导致
gz_fetch
从输入解压缩数据。换句话说,您的怀疑是对的:当您使用
gzseek

时,zlib确实将整个文件解压缩到该点。简短回答:由于deflate流的串行性质,
gzseek()
必须解码从启动到请求的seek点的所有压缩数据。所以你无法从你所做的事情中获得任何收益。事实上,所花费的总周期将随着压缩数据长度的平方而增加!所以不要这样做。

通常大部分时间都花在数据读取上。不是在减压。将您的数据放在最快的可用媒体上,然后重试。@GMichael谢谢您的提示。我做了一个实验,对两个压缩文件运行相同的程序,一个压缩级别较高,大小为600M,另一个压缩级别较低,但大小为2G。第一个文件用了22秒,而后者用了10秒。所以这很可能是因为解压。可能尝试在每个线程中使用相同的文件句柄,而不是打开它separately@fandin如果是这种情况,请检查CPU上的负载。您应该看到,所有CPU在性能方面都有好处。顺便说一下,不要打开太多的线程。上下文切换需要时间。@范斌试着为每个线程复制
gf
结构给我一个教科书上的极客/黑客示例。谢谢
state->seek = 1;
state->skip = offset;
if (state->seek) {
    state->seek = 0;
    if (gz_skip(state, state->skip) == -1)
        return -1;
}