1

簡単に並列化できる単純なタスクがあります。基本的に、同じ操作を(大きな数Gbの)入力ファイルの各行で繰り返し実行する必要があります。これのマルチスレッドバージョンを作成しているときに、I/Oがボトルネックであることに気付きました。私は、循環バッファにできるだけ速く進んで直接読み取る単一の「ファイルリーダー」スレッドを含むユーティリティクラスを構築することにしました。次に、複数のコンシューマーがこのクラスを呼び出して、「次の行」を取得できます。n個のスレッドが与えられた場合、各スレッドiの開始行はファイル内の行iであり、そのスレッドの後続の各行はnを追加することによって検出されます。これにはロックは必要ないことがわかりました。不変条件を保持するには、いくつかの主要なアトミック操作で十分です。

私はコードをテストしました、そしてそれはより速いようです、しかし考え直して、私は理由がわかりません。大きなファイルをn個の入力ファイルに分割し(同じファイルを「シーク」して同じことを実現し、前処理を最小限に抑えることができます)、各プロセスでiostream::readLineを呼び出すのも同じくらい速いのではないでしょうか。独自のチャンク?(iostreamは独自のバッファーにも読み込むため)。ワーカーは実際には同じデータ行を操作していないため、複数のスレッド間で単一のバッファーを共有することには固有の利点はないようです。さらに、同じ行で機能するように並列化することを考えない良い方法はありません。私は自分が見ているパフォーマンスの向上を理解し、それが「フルーキー」なのか、プラットフォーム間でスケーラブル/再現可能なのかを知りたいだけです...

4

2 に答える 2

0

I/O が制限されている場合は、2 つのスレッドを使用して高速化を実現できます。1 つはファイルを読み取り、もう 1 つは処理を実行します。この方法では、読み取りが処理を待つことはなく (最後の行を期待して)、100% の読み取りを行うことになります。

バッファーは、コンシューマー スレッドが一度に十分な作業を行うのに十分な大きさである必要があります。これは、ほとんどの場合、複数行で構成する必要があることを意味します (少なくとも 4000 文字をお勧めしますが、おそらくそれ以上をお勧めします)。これにより、スレッド コンテキストの切り替えコストが非現実的に高くなるのを防ぐことができます。

シングルスレッド:

  • 読む 1
  • プロセス1
  • 読む 2
  • プロセス2
  • 読む 3
  • プロセス3

ダブルスレッド:

  • 読む 1
  • プロセス 1/読み取り 2
  • プロセス 2/読み取り 3
  • プロセス3

一部のプラットフォームでは、オーバーラップ I/O を使用して、スレッドを使用しなくても同じスピードアップを得ることができますが、スレッドを使用するとより明確になることがよくあります。

実際に I/O バウンドである限り、複数のコンシューマ スレッドを使用してもメリットはありません。

于 2013-02-05T20:25:08.070 に答える
0

あなたの場合、プログラムが競合する少なくとも 2 つのリソース、CPU とハードディスクがあります。シングル スレッドのアプローチでは、データを要求し、アイドル状態の CPU で HD がデータを配信するのを待ちます。次に、HD がアイドル状態のときにデータを処理します。2 つのリソースのうちの 1 つが常にアイドル状態であるため、これは好ましくありません。複数の CPU または複数の HD がある場合、これは少し変わります。また、場合によっては、メモリ帯域幅 (つまり、RAM 接続) も制限リソースになります。

さて、あなたのソリューションは正しいです。1 つのスレッドを使用して HD をビジー状態に保ちます。このスレッドが HD の待機をブロックした場合、OS は単にデータを処理する別のスレッドに切り替えます。データがない場合は、ある程度待機します。そうすることで、CPU と HD が並行して動作し、少なくとも一定の時間は全体のスループットが向上します。複数の CPU があり、HD ではなく CPU が制限要因でない限り、3 つ以上のスレッドでスループットを向上させることはできないことに注意してください。一部のデータも書き戻す場合は、2 番目のハードディスクに書き込む 3 番目のスレッドを使用してパフォーマンスを向上させることができます。そうしないと、スレッドを増やしても何の利点も得られません。

于 2013-02-06T22:18:33.717 に答える