2016-08-16 6 views
0

私はC#で達成するのはかなり簡単な作業です。ユーザーは私に大きなバイナリファイル(数十GBのサイズ)を表すストリームを与えます。このファイルはたくさんのブロックから構成されています。私は各ブロックを読む必要があります。各ブロックでCPU集約的な分析を実行します。ユーザーに結果を正しい順序で伝えます。擬似コードでは、このコードは次のようになります。それだけでCPUを集中的分析のための1つのCPUコアを使用していますので、これは、ゆっくりと正常に動作しますが、並んだ入力と出力を持つ並列パイプライン

public IEnumerable<TResult> ReadFile(Stream inputStream) { 
    while(true) { 
     byte[] block = ReadNextBlock(stream); 
     if (block == null) { 
      break; // EOF 
     } 
     TResult result = PerformCpuIntensiveAnalysis(block); 
     yield return result; 
    } 
} 

。私がしたいのは、ブロックを1つずつ読み込み、並列に解析してから、ファイル内でブロックが検出されたのと同じ順序で結果をユーザーに返します。当然ながら、ファイル全体をメモリに読み込むことはできませんので、いつでもキューに保持するブロック数を制限したいと思います。

これには多くの解決策があり、私はカップルを試しました。しかし、何らかの理由で、私は非常に単純なアプローチを凌駕任意の解決策を見つけることができません。

public IEnumerable<TResult> ReadFile(Stream inputStream) { 
    while(true) { 
     var batch = new List<byte[]>(); 
     for (int i=0; i<BATCH_SIZE; i++) { 
      byte[] block = ReadNextBlock(stream); 
      if (block == null) { 
       break; 
      } 
      batch.Add(block); 
     } 
     if (batch.Count == 0) { 
      break; 
     } 
     foreach(var result in batch 
      .AsParallel() 
      .AsOrdered() 
      .Select(block => PerformCpuIntensiveAnalysis(block)) 
      .ToList()) { 
      yield return result; 
     } 
    } 
} 

私はTPL /データフローだけでなく、純粋に手動のアプローチを試してみた、そしてすべての場合には、私のコードを費やしていますほとんどの時間は同期を待っています。シリアルバージョンは約2倍の性能を発揮しますが、8コアのマシンではそれ以上の性能が期待できます。だから、私は何が間違っているの?

(私も、私は本当に私はちょうど簡潔にするため、ここでそれを使用しています、私のコードで「降伏を返す」ジェネレータパターンを使用していないことを明確にする必要があります。)

+0

問題を確実に再現する良い[mcve]がなければ、確かに知ることは不可能です。しかし、ボトルネックがCPUではなくI/Oである可能性を考慮する必要があります。 I/Oがボトルネックになっている場合は、牛が家に帰るまでスレッドとCPUコアを追加することができます。それでもやはりうまくいくわけではありません。 –

+0

@Peter Duniho:この他にどのような情報が必要ですか? I/OとCPUの面では、メモリバッファに小さなファイル(〜100 MB)をロードしてからテスト用のMemoryStreamとしてラップしようとしました。したがって、I/Oはボトルネック。 – Bugmaster

+0

プロファイラ(例:PerfView)を使用してボトルネックの発生場所を特定しようとしましたか? – easuter

答えて

1

は、ブロックサイズを最適化するようにしてください。

ブロックが少なすぎ、そのうちの1つが他のブロックよりもはるかに時間がかかる場合は、ほとんどすべての作業を1つのCPUで行う必要があります。

一方、ブロックが小さすぎると、TPLはタスク管理に関連するオーバーヘッドに多くの時間を費やします。

CPUよりもはるかに多くのブロックが必要です。これにより、TPLは作業をCPUに均等に分散させることができます。他方では、1つのブロックはかなりの計算作業を必要とするはずである。具体的な数字をつけるのは難しいです。

+0

バッファサイズを動的にスケーリングする良い方法をお勧めしますか?私はブロックのサイズを制御できません。またはむしろ、私は各ブロックが約64Kのサイズであることを知っていますが、処理にどれくらいの時間がかかるかわかりません。しかし、私はブロックを動的にバッチアップすることができます... – Bugmaster

+0

私はちょうど実験を行います。ブロックサイズを4倍小さくするか、ラガーにして、改善が見えるか悪化するかを見てみましょう。 –

関連する問題