4

最近、このSemaphoreSlimクラスを使用して、(大規模な)ストリーミングリソースで並列化可能な操作の進行中の作業を制限していることに気付きました。

// The below code is an example of the structure of the code, there are some 
// omissions around handling of tasks that do not run to completion that should be in production code

SemaphoreSlim semaphore = new SemaphoreSlim(Environment.ProcessorCount * someMagicNumber);
foreach (var result in StreamResults()) 
{
  semaphore.Wait();
  var task = DoWorkAsync(result).ContinueWith(t => semaphore.Release());
  ...
}

これは、メモリに多くの結果をもたらし、プログラムが対処できないことを回避するためです(通常はOutOfMemoryExceptionによって証明されます)。コードは機能し、適度にパフォーマンスが優れていますが、それでも不自然に感じます。特に、someMagicNumber乗数は、プロファイリングを介して調整されますが、最適ではない可能性があり、の実装の変更に対して回復力がありませんDoWorkAsync

スレッドプールが実行のために多くのものをスケジュールするという障害を克服できるのと同じように、利用可能なリソースに基づいてメモリにロードされる多くのものをスケジュールするという障害を克服できるものが欲しいです。

OutOfMemoryExceptionが発生するかどうかを決定論的に決定することは不可能であるため、私が探しているものは統計的手段によってのみ達成できるか、まったく達成できない可能性があることを理解していますが、何かが欠けていることを願っています。

4

1 に答える 1

1

ここで、あなたはおそらくこの問題を考えすぎていると思います。オーバーシュートの結果はかなり高くなります(プログラムがクラッシュします)。低すぎると、プログラムの速度が低下する可能性があります。最小値を超えるバッファがまだある限り、パイプ内のそのタスクの処理時間が非常に不安定でない限り、バッファをさらに増やしても、通常、ほとんどまたはまったく効果がありません。

バッファが常にいっぱいになっている場合は、通常、パイプ内の前のタスクが後続のタスクよりもかなり速く実行されることを意味します。したがって、バッファがかなり小さい場合でも、後続のタスクに何らかの作業が確実に行われる可能性があります。 。バッファの利点の90%を取得するために必要なバッファサイズは、通常、非常に小さくなります(おそらく数十アイテム)が、OOMエラーを取得するために必要な側は、6以上高くなります。あなたがこれらの2つの数字の間のどこかにいる限り(そしてそれは着陸するのにかなり大きな範囲です)、あなたは大丈夫です。

静的テストを実行し、静的な数値を選択し、「万が一に備えて」のために数パーセント余分に追加するだけで、問題はありません。せいぜい、入力データやマシンの仕様が大幅に変更された場合に再コンパイルせずに変更できるように、いくつかのマジックナンバーを構成ファイルに移動します。

于 2012-06-22T15:45:31.393 に答える