6

多分私はそれを正しく理解していませんでした...すべてのParallelクラスの問題:(

しかし、私が今読んでいることから、私がParallelを使用するとき、私は実際にいくつかのタスク/ミッションのためにthreadPoolに存在するすべてのスレッドを動員することを理解しています。

  var arrayStrings = new string[1000];
  Parallel.ForEach<string>(arrayStrings, someString =>
  {
       DoSomething(someString);
  });

したがって、この場合のParallel.ForEachは、「DoSomething」タスク/ミッションのためにthreadPoolに存在するすべてのスレッドを動員しています。

しかし、Parallel.ForEachを呼び出すと、新しいスレッドが作成されますか?

1000の新しいスレッドがないことは明らかです。しかし、1000個の新しいスレッドがあると仮定しましょう。threadPoolが保持しているすべてのスレッドを解放する場合もあります。この場合、Parallel.ForEachは新しいスレッドを作成しますか?

4

4 に答える 4

11

簡単な答え: Parallel.ForEach()「すべてのスレッドを動員する」わけではありません。ThreadPoolまた、 (実行する)上で何らかの作業をスケジュールする操作によりParallel.ForEach()、プールに新しいスレッドが作成される可能性があります。

長い答え: これを正しく理解するには、3 つのレベルの抽象化がどのように機能するかを知る必要があります: Parallel.ForEach()TaskSchedulerおよびThreadPool:

  1. Parallel.ForEach()(およびParallel.For()) で作業をスケジュールしTaskSchedulerます。スケジューラを明示的に指定しない場合、現在のスケジューラが使用されます。

    Parallel.ForEach()作業をいくつかの s に分割しますTask。それぞれTaskが入力シーケンスの一部を処理し、それが完了すると、別の部分が利用可能であればそれを要求します。

    Tasks はParallel.ForEach()いくつ作成されますか? が実行できるようTaskSchedulerにします。これが行われる方法は、実行を開始するときに最初に自分自身のコピーをキューに入れることです (設定した場合にTask違反しない限り)。MaxDegreeOfParallelismこのようにして、実際の同時実行レベルはTaskScheduler.

    また、がサポートしているTask場合、最初のスレッドは現在のスレッドで実際に実行されますTaskScheduler(これは を使用して行われRunSynchronously()ます)。

  2. デフォルトTaskSchedulerでは、それぞれTaskをキューに入れるだけですThreadPoolTask(実際には、別の から開始する場合はより複雑になりますTaskが、ここでは関係ありません。) 他TaskSchedulerの はまったく異なることを行うことができ、それらの一部 ( などTaskScheduler.FromCurrentSynchronizationContext()) は での使用にはまったく適していませんParallel.ForEach()

  3. ThreadPool非常に複雑なアルゴリズムを使用して、特定の時間に実行するスレッド数を正確に決定します。ただし、ここで最も重要なことは、新しい作業項目をスケジュールすると、新しいスレッドが作成される可能性があるということです (必ずしもすぐにではありません)。また、Parallel.ForEach()では、実行するためにキューに入れられたアイテムが常に存在するThreadPoolため、スレッドの数を決定するのは の内部アルゴリズムに完全に依存します。

まとめると、 によって使用されるスレッドの数を決定することはほとんど不可能Parallel.ForEach()です。これは、多くの変数に依存するためです。ループが現在のスレッドで完全に同期して実行され、各アイテムが独自の新しく作成されたスレッドで実行されるという両極端が可能です。

ただし、一般的には、最適な効率に近いはずであり、おそらくこれらすべての詳細について心配する必要はありません。

于 2012-06-01T17:15:42.567 に答える
1

私はあなたがこれを間違った方法で持っていると思います。PATTERNS OF PARALLEL PROGRAMMINGから、Parallel.ForEach がまさにシンタックス シュガーであることがわかります。

Parallel.ForEach は、大まかに次のようなものに要約されます。

for (int p = 0; p < arrayStrings.Count(); p++)
{
    ThreadPool.QueueUserWorkItem(DoSomething(arrayStrings[p]);
}

ThreadPool がスケジューリングを処理します。興味があれば、ThreadPool のスケジューラがある程度どのように動作するかについての優れた記事がいくつかありますが、それは TPL とは関係ありません。

于 2012-06-01T12:29:08.070 に答える
1

Parallel.Foreach は新しいスレッドを作成せず、「すべてのスレッドを動員」しません。スレッドプールから限られた数のスレッドを使用し、それらにタスクを送信して並列実行します。現在の実装では、デフォルトでコアごとに 1 つのスレッドが使用されます。

于 2012-06-01T12:23:49.117 に答える
0

Parallel はスレッドをまったく処理しません。TASKS をタスク フレームワークにスケジュールします。その後、スケジューラがあり、デフォルトのスケジューラがスレッドプールに移動します。これはグー数のスレッドを見つけようとし (4.0 よりも 4.5 の方が優れています)、スレッドプールはゆっくりと新しいスレッドをスピンアップする可能性があります。

しかし、それは parallel.foreach の関数ではありません;)

Parallel.ForEach は新しいスレッドを作成しますか???

それは決してありません。私が言ったように、1000 の foreach があり、10.000 のタスクをキューに入れます。タスク ファクトリ スケジューラは、プログラムされていることを実行します ((置き換えることができます)。一般に、デフォルト - はい、ゆっくりと新しいスレッドが理由の範囲内で発生します。

于 2012-06-01T12:27:58.663 に答える