2

背景: 私の質問が曖昧すぎないことを願っています。影響を受けるメソッドは非常に複雑で時間がかかるため、可能な限り説明し、あまり多くのコードを投稿することはできません。したがって、私の問題は、複数のスレッドで処理を高速化しようとしていることです。このアプリケーションは、2Dゲームエンジンの照明用であり、シーンの上部にさまざまな透明度レベルの黒い長方形を描画します(これにより現在ラグが発生しています)。

私にとっての最初のステップは、同じ光レベルの隣接する長方形をバッチ処理して、レンダリング作業を減らすことでした。これはうまくいきました(おそらくそれはもっとうまくいくかもしれませんが、今のところ重要ではありません)、そして今私は粗いスレッドシステムも実装しました。

私の質問の核心:上記の特定のバッチ処理方法のタイミングを分析しているときに(別々のばらばらのデータセットで動作するスレッドの数が異なる場合)、いくつかの奇妙なスパイクに気づきました。以前は、1つのスレッドで作業する場合、メソッドの実行には約12ミリ秒かかり、15ミリ秒に奇妙なジャンプがありました。あまり考えていませんでした。ただし、2つまたは3つのスレッドで処理する場合、4〜5ミリ秒かかり、10ミリ秒にジャンプし、場合によっては20ミリ秒にもなります。

今では、コードを調べないと原因がわからないことに気付いたので、そうは思いません。むしろ、私はいくつかの結論を導き出そうとしており、今それらを確認したいと思います。前に述べたように、各スレッドは私のデータセットの一部で機能し、互いに完全に切り離されています(それらは重複していません)。ただし、データ配列へのエントリポイントは、特定のクラスの同じインスタンスの同じメソッドを経由します。したがって、スレッドはすべて同じ方法で同じ配列にアクセスします(ただし、その一部は別々です。このため、ロックも使用しません)。これにより、予期しない速度低下が発生する可能性がありますか?

それとも、スレッドがこのように動作するのはおそらく正常な動作ですか(実行時間は標準の2倍以上に変化します)?別の注意点として、必要なときにすべてのスレッドを作成し、実行して完了させます。

データセットへのアクセス方法:

public short GetLightLevelAt(int x, int y)
{
   if (inLightingBounds(x, y))
   {
      return lightData[x, y];
   }
   else
   {
      return GuessLightLevelAt(x,y); //This won't ever happen currently, guaranteed
   }
}
4

4 に答える 4

2

おそらく、データセットが CPU キャッシュを破棄するほど大きく、パフォーマンスに一貫性がありませんか? 複数レベルのキャッシュがあり、それを制御する方法がないため、何かがどれだけかかるかを正確に知ることはできません.

たとえば、データがプロセッサ上の最も親密なキャッシュ サイズと同じくらい大きい場合、1 つのスレッドから 3 つのスレッドに移行すると、それ以外の場合に得られるパフォーマンス上の利点を効果的に失うことになります。場合によっては、物事を 1 つずつ順番に行う方が良い場合があります。

于 2012-06-20T22:09:11.490 に答える
2

あなたの場合、スパイクが高いため、上記のガベージコレクションまたはコンテキストスイッチングに関係している可能性があります。

ただし、同じアレイ上でマルチスレッドを実行すると、偽の共有が原因で速度が低下する場合があります。(パーティションが重複していない場合でも)

たとえば、次のコードでは、偽共有の問題が発生する可能性があります。

int[] array = new int[100000];
int a = 1;
int b = 0;

//The following loops run concurrently

//Thread A
for( int i = 0; i < 50000; i++ )
    array[i] = a;

//Thread B
for( int j = 50000; j < 100000; j++ )
    array[j] = b;

int a と b が互いに隣接して宣言されており、互いに同じキャッシュ ライン上にある可能性が非常に高いため、誤った共有が発生します。

同時に実行すると、このコードはまったくスピードアップせず、場合によってはスローダウンする可能性があります。

于 2012-06-22T00:00:22.530 に答える
1

発生しているオーバーヘッドは、コンテキストの切り替えまたはリソースの競合が原因である可能性があります。使用可能なコアが最大になると、OS はコンテキストの切り替えを開始します (基本的には、あるプロセス/スレッドから別のプロセス/スレッドに移動します)。

ただし、コードを投稿しないとわかりにくいです。

于 2012-06-20T22:12:04.343 に答える
1

そのメソッドを実行するために少数のスレッドから多数のスレッドに切り替えるとレイテンシが発生する可能性があるかどうかを尋ねました。短い答えはノーです。

そのアレイをロックしていないので、競合とは関係ありません。

GC はコードのランダムな部分に表示されるため、特定の場所ではなく、あちこちにスパイクが表示されます。

これはスパイクではないと思います。これはコンテキストスイッチです。あなたの時計の解像度はおそらく高く、量子サイズも高くなっています。そのため、1 つのコンテキスト スイッチでスレッドが長時間停止します。

これが問題の原因である場合は、スレッドの数を減らす必要があります。あなたはそれを可能な限り遅くしています。

于 2012-06-21T01:28:42.363 に答える