2016-06-24 42 views
3

複数のスレッドからgzip圧縮ファイルを読み込もうとしています。C++/C gzファイルを同時に読み取る複数のスレッド

gzread複数のスレッド内の関数が(gseekを使用して)異なるファイルオフセットから開始するため、ファイルのさまざまな部分を読み込むので、これにより解凍プロセスが大幅に高速化されると考えていました。

単純化されたコードは、驚いたことに

// in threads 
auto gf = gzopen("file.gz",xxx); 
gzseek(gf,offset); 
gzread(xx); 
gzclose(gf); 

のようなものです、私のマルチスレッド版のプログラムは全くないスピードアップを行います。 20スレッドバージョンは、シングルスレッドバージョンとまったく同じ時間を使用します。私はこれがディスクのボトルネックから遠いと確信しています。

私は、zlibのインフレ機能が、小さな部分でもファイル全体を解凍する必要があるかもしれないと思っていますが、私はマニュアルから手がかりを得られませんでした。

誰かが私の場合にスピードアップする方法を知っていますか?

+0

通常、ほとんどの時間はデータの読み取りに費やされます。減圧ではない。最も速い利用可能なメディアにあなたのデータを置き、もう一度やり直してください。 – GMichael

+0

@GMichael手がかりをありがとう。私は、同じプログラムを2つの圧縮ファイルに対して実行しました.1つは600Mの圧縮レベルが高く、もう1つは低レベルですが2Gサイズです。最初のファイルは22秒、後者は10秒でした。したがって、圧縮解除の可能性が高くなります。 – fanbin

+0

各スレッドで同じファイルハンドルを使用し、別々に開こうとしないでください –

答えて

1

tl; dr:zlibはランダムアクセス用に設計されていません。It seems possible to implementがありますが、インデックスを作成するための完全なリードスルーが必要なので、あなたのケースでは役に立たないかもしれません。

zlib sourceを見てみましょう。 gzseekが含まれ、gzseek64のラッパーです:

/* if within raw area while reading, just go there */ 
if (state->mode == GZ_READ && state->how == COPY && 
     state->x.pos + offset >= 0) { 

「生の面積の中で、」我々はgzipで圧縮されたファイルを処理している場合はかなり右鳴りません。 gzguts.hstate->howの意味を調べてみましょう:

int how; /* 0: get header, 1: copy, 2: decompress */ 

右。 gz_openの終わりには、gzseek64に戻って0にgz_resetセットhowへの呼び出しは、我々は状態に、この変更で終わる:

state->seek = 1; 
state->skip = offset; 

gzread、と呼ばれる、gz_skipへの呼び出しでこれを処理します。

少しだけ、さらに、このウサギの穴に続き
if (state->seek) { 
    state->seek = 0; 
    if (gz_skip(state, state->skip) == -1) 
     return -1; 
} 

、我々はgz_fetchまでgz_skip呼び出しgz_fetchが希望追求のための十分な入力を処理したことがわかります。 gz_fetchは、最初のループ反復でstate->how = GZIPを設定するgz_lookを呼び出します。これにより、gz_fetchは入力からデータを解凍します。言い換えれば、あなたの疑惑は正しいです:zlibは、gzseekを使用すると、その時点までファイル全体を解凍します。

+0

教科書のオタク/ハックの例が私にあります。ありがとう – fanbin

1

zlibの実装ではマルチスレッド化されていません(http://www.zlib.net/zlib_faq.html#faq21 - "zlibスレッドセーフですか? - はい...もちろん、一度に1つのスレッドからzlibまたはgzipストリームを操作する必要があります)。シークレットポジションまで「ファイル全体」を解凍します。

zlibフォーマットでは、パラレル圧縮解除/シークを有効にするために、不適切なアライメント(ビットアライメント)/オフセットフィールドなし(deflate format)があります。

あなたは、zの別の実装をしてみてください(膨らませる/収縮)、例えば、http://zlib.net/pigz/(または非zlibの近代的な並列形式にシングルコアの時代から古代の圧縮からの切り替え、XZグーグルから/ LZMA /何か)も

pigz(gzipの並列実装を表す)は、データを圧縮するときに複数のプロセッサと複数のコアを悪用するgzipを完全に機能的に置き換えるものです。 pigzはMark Adlerによって書かれ、zlibとpthreadライブラリを使用しています。 pigzをコンパイルして使用するには、ソースコード配布のREADMEファイルをお読みください。あなたは読むことができますpigz manual page here.

マニュアルページはhttp://zlib.net/pigz/pigz.pdfであり、有用な情報があります。

それはZLIBに互換性のあるフォーマットを使用するが、圧縮を平行に採用:

各部分生のdeflateストリームが空に格納されたブロックで終了...バイト境界でその部分ビットストリームを終了するために。

さらに

、フォーマットを収縮は、並列伸張のために悪い:

解凍は、特別に準備されたDEFLATEは、その目的のためにストリームを少なくともしないことなく、並列化することができません。 Asaresult、pigzは、解凍のために単一のスレッド(メインスレッド)を使用しますが、読み取り、書き込み、およびチェック計算のための3つの他のスレッドを作成し、状況によっては圧縮解除を高速化できます。

3

短い答え:デフレートされたストリームのシリアルな性質のため、gzseek()は、圧縮データのすべてを開始から要求されたシークポイントまでデコードする必要があります。それで、あなたがしようとしていることで何の利益も得られません。事実、圧縮されたデータの長さの2乗に伴って消費される総サイクル数は増加します!そうしないでください。

関連する問題