23

そして、「同じこと」とは、これら 2 つの操作が基本的に同じ作業を行うことを意味します。つまり、作業する必要があるものに基づいて、どちらを呼び出すのがより便利であるかということです。(つまり、デリゲートのリストまたは反復するもののリスト)? MSDN、StackOverflow、およびさまざまなランダムな記事を検索してきましたが、これに対する明確な答えをまだ見つけていません。

編集: もっと明確にすべきでした。2 つの方法が同じことを行うかどうかを尋ねているのは、そうでない場合、どちらがより効率的かを理解したいからです。

例: 500 個のキー値のリストがあります。現在foreach、リストを (シリアルに) 反復処理し、各項目に対して作業を実行するループを使用しています。複数のコアを利用したい場合は、Parallel.ForEach代わりに単純に使用する必要がありますか?
議論のために、これらの 500 のタスクに対して 500 のデリゲートの配列があるとしましょう。500 のデリゲートParallel.Invokeのリストを呼び出して与えることで、最終的な効果は異なるでしょうか?

4

4 に答える 4

32

Parallel.ForEach要素のリストを調べて、配列の要素に対していくつかのタスクを実行できます。

例えば。

Parallel.ForEach(val, (array) => Sum(array));

Parallel.Invoke多くの関数を並行して呼び出すことができます。

例えば。

Parallel.Invoke(
() => doSum(array),
() => doAvg(array),
() => doMedian(array));

上記の例からわかるように、機能が異なることがわかります。の要素をForEach反復処理し、各要素に対して1つのタスクを並行して実行しますが、1つの要素に対して多数のタスクを並行して実行できます。ListInvoke

于 2012-06-03T02:18:10.530 に答える
11

Parallel.InvokeとParallel.ForEach(アクションの実行に使用される場合)は同じように機能しますが、コレクションを配列にする必要があります。次のサンプルについて考えてみます。

List<Action> actionsList = new List<Action>
            {
                () => Console.WriteLine("0"),
                () => Console.WriteLine("1"),
                () => Console.WriteLine("2"),
                () => Console.WriteLine("3"),
                () => Console.WriteLine("4"),
                () => Console.WriteLine("5"),
                () => Console.WriteLine("6"),
                () => Console.WriteLine("7"),
                () => Console.WriteLine("8"),
                () => Console.WriteLine("9"),
            };

            Parallel.ForEach<Action>(actionsList, ( o => o() ));

            Console.WriteLine();

            Action[] actionsArray = new Action[]
            {
                () => Console.WriteLine("0"),
                () => Console.WriteLine("1"),
                () => Console.WriteLine("2"),
                () => Console.WriteLine("3"),
                () => Console.WriteLine("4"),
                () => Console.WriteLine("5"),
                () => Console.WriteLine("6"),
                () => Console.WriteLine("7"),
                () => Console.WriteLine("8"),
                () => Console.WriteLine("9"),
            };

            Parallel.Invoke(actionsArray);

            Console.ReadKey();

このコードは、1回の実行でこの出力を生成します。通常、出力の順序は毎回異なります。

0 5 1 6 2 7 3 8 4 9

0 1 2 4 5 6 7 8 9 3

于 2012-06-03T02:20:08.330 に答える
1

驚くべきことに、それらは同じものではありません。基本的な違いは、例外が発生した場合の動作です。

  1. Parallel.ForEachおよびParallel.For今後のParallel.ForEachAsync)はすぐに失敗します。例外が発生すると、新しい並列作業は開始されず、現在実行中のすべてのデリゲートが完了するとすぐに戻ります。
  2. Parallel.Invoke、アクションの一部 (またはすべて) が失敗したかどうかに関係なく、常にすべてのアクションを呼び出します。

この動作を実証するために、1,000 個のアクションを並行して実行してみましょう。3 つのアクションのうち 1 つが失敗します。

int c = 0;
Action[] actions = Enumerable.Range(1, 1000).Select(n => new Action(() =>
{
    Interlocked.Increment(ref c);
    if (n % 3 == 0) throw new ApplicationException();
})).ToArray();

try { c = 0; Parallel.For(0, actions.Length, i => actions[i]()); }
catch (AggregateException aex)
{ Console.WriteLine($"Parallel.For, Exceptions: {aex.InnerExceptions.Count}/{c}"); }

try { c = 0; Parallel.ForEach(actions, action => action()); }
catch (AggregateException aex)
{ Console.WriteLine($"Parallel.ForEach, Exceptions: {aex.InnerExceptions.Count}/{c}"); }

try { c = 0; Parallel.Invoke(actions); }
catch (AggregateException aex)
{ Console.WriteLine($"Parallel.Invoke, Exceptions: {aex.InnerExceptions.Count}/{c}"); }

出力 (私の PC、.NET 5、リリース ビルド):

Parallel.For, Exceptions: 5/12
Parallel.ForEach, Exceptions: 5/11
Parallel.Invoke, Exceptions: 333/1000

Fiddle で試してみてください

于 2021-09-12T15:39:38.057 に答える
0

私はそれを言い表す良い方法を見つけようとしています。しかし、それらは同じものではありません。

その理由は、Invoke が Action の配列で機能し、ForEach が Action の List (具体的には IEnumerable) で機能するためです。リストは配列とは仕組みが大きく異なりますが、基本的な動作は同じです。

私にはわからないので、違いが実際にを伴うのかはわかりません.

良い質問にも+1。

編集; 別の答えもあることに気づきました。Invoke は、アクションの動的リストで機能します。ただし、Foreach はアクションのジェネリック IEnumerable と連携でき、条件付きロジック、アクションごとのアクションを使用できます。したがって、各 Foreach 反復で Action.Invoke() と言う前に条件をテストできます。

于 2012-06-03T01:57:21.333 に答える