そのため、私のマルチスレッド プログラムは、gzip が正常に解凍できるものを出力できず、他の問題が発生する可能性があることを前置きします。しかし、私が気付いたのは、シングルスレッドとマルチスレッドの各ブロックの圧縮サイズが根本的に異なるということです。
私のシングルスレッド実行では、SYNC_FLUSH が設定された GZIPOutputStream(System.out, true) があります。バッファがいっぱいになるまで、system.in から継続的に読み取ります。
GZIPOutputStream compressor = new GZIPOutputStream(System.out, true);
bytesRead = inBytes.read(buff,0,BLOCK_SIZE);
....
while(bytesRead != -1)
{
offset += bytesRead;
if (offset == BLOCK_SIZE)
{
compressor.write(buff,0,offset);
compressor.flush();
offset = 0;
}
if((bytesRead=inBytes.read(buff,offset,BLOCK_SIZE-offset)) == -1) {
compressor.write(buff,0,offset);
compressor.finish();
}
}
compressor.close();
ご覧のとおり、バッファーがいっぱいになった後、コンプレッサに出力への書き込みを指示し、次にフラッシュを呼び出します。は、残りの出力を強制的に圧縮してフラッシュすることを保証するため、再度書き込みを行うときに、バッファーにデータが残っていません。
したがって、元の入力が最初からその長さであったかのように非常に似ています (したがって、各ブロックは独自の個別のストリームです)。
したがって、私のマルチスレッド プログラムでは、1 つの GZIPOutputStream の書き込みとフラッシュを行う代わりに、それぞれが独自の GZIPOutputStream を持つ一連のスレッドを使用するだけです。基本的に、その部分をスレッドへの呼び出しに置き換えます
List<Future<byte[]>> results = new ArrayList<Future<byte[]>>();
bytesRead = inBytes.read(buff,0,BLOCK_SIZE);
while(bytesRead != -1)
{
offset += bytesRead;
if (offset == BLOCK_SIZE)
{
results.add(exec.submit(new workerThread(buff,offset)));
offset = 0;
}
if((bytesRead=inBytes.read(buff,offset,BLOCK_SIZE-offset)) == -1) {
results.add(exec.submit(new workerThread(buff,offset)));
}
}
圧縮するためにバッファを渡すだけです。私のスレッドが行うことはすべて
private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
private byte[] finalOut;
....
public byte[] call() {
try{
GZIPOutputStream compress = new GZIPOutputStream (bOut, true);
compress.write(input,0,size);
compress.flush();
compress.close();
}
catch (IOException e)
{
e.printStackTrace();
System.exit(-1);
}
finalOut = bOut.toByteArray();
return finalOut;
}
私が文字通り行ったことは、スレッドに圧縮ジョブを与えたことだけだと思います。私は他に何も変更しませんでした。しかし、マルチスレッド プログラムを実行して結果を 16 進ダンプすると、通常、2 つのプログラム間で各ブロックが大きく異なることに気付きました。小さなバッファと小さな入力を使用したので、読みやすくなりました。
マルチスレッド プログラムで crc エラーが発生しました。これは、少なくとも gzip が形式を認識し、解凍を開始したことを意味します。それが完了したとき、最終結果がCRCから期待されたものと一致しないというだけです(解凍された出力のサイズなど)。
正直なところ、なぜこれが起こるのかわかりません。もっと明白なエラーを期待していたでしょうが、これは非常にランダムに見えます。確実に圧縮しています。そして、シングルスレッドプログラムとマルチスレッドプログラムの間の最初の数バイト (もちろんヘッダーの後) はしばしば同じであるため、順不同で連結しているとは思いません (さらに、executor.get() 関数はそれを処理する必要があります)。 .
私はただ困惑しています。gzip は連結されたストリームを解凍できることを知っています。入力を文字通り半分に分割して個別に出力し、それらをシングルスレッド プログラムで結合すると、問題なく解凍されました。
記録のために、328 個の「A」文字を含むファイルで試しただけなので、それほど大きくはありません。単一スレッドの GZIPOutputStream の 16 進ダンプは次のとおりです。
0000000 8b1f 0008 0000 0000 0000 7472 581c 0000
0000010 0000 ffff 681a 0004 0000 ffff 21a2 02e2
0000020 0000 ff00 03ff a800 5bff 5c79 0001 0000
マルチスレッドの場合は
0000000 8b1f 0008 0000 0000 0000 7472 19a4 22e0
0000010 1146 0000 ff00 03ff 7500 5f6c 80d1 0000
0000020 1f00 088b 0000 0000 0000 a200 e221 4622
0000030 0011 0000 ffff 0003 6c75 d15f 0080 0000
0000040 8b1f 0008 0000 0000 0000 21a2 02e2 0000
0000050 ff00 03ff 8a00 193b 5c21 0000 0000
彼らはかなり違います。
うわー、これは本当に長くなりました。申し訳ありません。本当に困惑して立ち往生しました。