このforeachコードをParallel.ForEachに変換するにはどうすればよいですか?


180

私は少し混乱していParallel.ForEachます。
それは何でParallel.ForEachあり、それは正確に何をしますか?
MSDNリンクを参照しないでください。

簡単な例を次に示します。

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);

foreach (string line in list_lines)
{
    //My Stuff
}

この例をどのように書き換えることができParallel.ForEachますか?


これは、ここで回答されている場合がありますstackoverflow.com/questions/3789998/...
Ujjwal Manandhar

1
@UjjwalManandhar ParallelクラスとPLINQの使用の違いについて質問しているため、実際にはかなり異なります。
リードコプシー、2012

18
他の人はあなたがどのように書き直すことができるか答えました。それでそれは何をしますか?通常どおり、コレクション内の各アイテムに対して「アクション」を実行しますforeach。違いは、並列バージョンは多くの「アクション」を同時に実行できることです。ほとんどの場合(コードを実行しているコンピューター、コードの混み具合、その他の要素によって異なります)、処理速度は速くなり、それが最も重要な利点です。並行して実行すると、アイテムが処理される順序がわかりません。通常の(シリアル)foreachでは、lines[0]最初に来ることが保証され、次にlines[1]となります。
Jeppe Stig Nielsen 2012

1
@JeppeStigNielsen並列化にはかなりのオーバーヘッドがあるため、常に高速になると限りません。これは、反復するコレクションのサイズとその内部のアクションによって異なります。正しいことは、Parallel.ForEach()の使用とforeach()の使用の違いを実際に測定することです。多くの場合、通常のforeach()の方が高速です。
デイブブラック

3
@DaveBlack確かに。どちらの場合も、それが速いか遅いかを測定する必要があります。私は一般的に並列化について説明しようとしていました。
Jeppe Stig Nielsen

回答:


126
string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);
Parallel.ForEach(list_lines, line =>
{
    //Your stuff
});

6
ただそれを指摘したかったので(OPについてはもっと)、それだけで機能するという誤った考えがなかったList<T>;)
Reed Copsey

1
注意と回答をありがとう。HASHリストを使用して重複するアイテムを削除するため、コードでList <string>を使用しました。通常の配列では、重複を簡単に削除することはできません:)。
SilverLight

119
元の投稿の質問「Parallel.ForEachとは何で、正確に何をするのか」についての説明がないため、この回答が正しい回答としてマークされていると混乱します...
fose

6
@fosb問題は、質問のタイトルが完全に意味を変更するように編集されたことです...したがって、この回答はもはや意味がありません。そうは言っても、それはまだ悪い答えです
aw04

274

foreachループ:

  • 反復は1つずつ順番に行われます
  • foreachループは、単一のスレッドから実行されます。
  • foreachループは.NETのすべてのフレームワークで定義されています
  • 遅いプロセスは連続して実行されるため、 実行が遅くなる可能性があります
    • プロセス2は、1が完了するまで開始できません。プロセス3は、2&1が完了するまで開始できません...
  • スレッド化のオーバーヘッドがないため、迅速なプロセスの実行が高速化されます。

Parallel.ForEach:

  • 実行は並行して行われます。
  • Parallel.ForEachは複数のスレッドを使用します。
  • Parallel.ForEachは、.Net 4.0以降のフレームワークで定義されています。
  • 実行が遅いプロセスが可能速く、それらを並列に実行することができますよう、
    • プロセス1、2、および3 同時に実行できます(以下の例の再利用されたスレッドを参照)
  • スレッド化のオーバーヘッドが増えるため、迅速なプロセスの実行が遅くなる可能性があります

次の例は、従来のforeachループと

Parallel.ForEach()の例

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace ParallelForEachExample
{
    class Program
    {
        static void Main()
        {
            string[] colors = {
                                  "1. Red",
                                  "2. Green",
                                  "3. Blue",
                                  "4. Yellow",
                                  "5. White",
                                  "6. Black",
                                  "7. Violet",
                                  "8. Brown",
                                  "9. Orange",
                                  "10. Pink"
                              };
            Console.WriteLine("Traditional foreach loop\n");
            //start the stopwatch for "for" loop
            var sw = Stopwatch.StartNew();
            foreach (string color in colors)
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            Console.WriteLine("foreach loop execution time = {0} seconds\n", sw.Elapsed.TotalSeconds);
            Console.WriteLine("Using Parallel.ForEach");
            //start the stopwatch for "Parallel.ForEach"
             sw = Stopwatch.StartNew();
            Parallel.ForEach(colors, color =>
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            );
            Console.WriteLine("Parallel.ForEach() execution time = {0} seconds", sw.Elapsed.TotalSeconds);
            Console.Read();
        }
    }
}

出力

Traditional foreach loop
1. Red, Thread Id= 10
2. Green, Thread Id= 10
3. Blue, Thread Id= 10
4. Yellow, Thread Id= 10
5. White, Thread Id= 10
6. Black, Thread Id= 10
7. Violet, Thread Id= 10
8. Brown, Thread Id= 10
9. Orange, Thread Id= 10
10. Pink, Thread Id= 10
foreach loop execution time = 0.1054376 seconds

Parallel.ForEachサンプルの使用

1. Red, Thread Id= 10
3. Blue, Thread Id= 11
4. Yellow, Thread Id= 11
2. Green, Thread Id= 10
5. White, Thread Id= 12
7. Violet, Thread Id= 14
9. Orange, Thread Id= 13
6. Black, Thread Id= 11
8. Brown, Thread Id= 10
10. Pink, Thread Id= 12
Parallel.ForEach() execution time = 0.055976 seconds

63
Parallel.ForEachは(常に)高速であるというあなたの「主張」に本当に同意しません。これは、ループ内の操作の重さに依存します。これは、並列処理を導入するオーバーヘッドの価値がある場合とない場合があります。
Martao 2014年

1
さて、それぞれの並列とは、ループ本体でコードを実行するために個別のスレッドが設定されることを意味します。.NETにはこれを行うための効率的なメカニズムがありますが、これはかなりのオーバーヘッドです。したがって、単純な演算(合計や乗算など)のみが必要な場合は、並列foreachの方が速くなるはずはありません。
マルタオ2015

3
@Jigneshこれは良い測定例ではないので、これについてはまったく言及しません。「Thread.Sleep(10);」を削除します 各ループ本体から、もう一度試してください。
stenly 2015年

1
@Martaoは正しい、問題は並列アプローチが順次よりも長いオブジェクトロックのオーバーヘッドにあります。
stenly 2015年

8
@stenly私は、Sleepがまさにその良い例である理由だと思います。(Martaoが説明したように)単一の高速反復でPFEを使用することはありません-したがって、この答えは反復を遅くし、PFEの(正しい)利点が強調されます。これは答えで説明する必要があることに私は同意しますが、太字の「常に速い」は非常に誤解を招くものです。
mafu

43
string[] lines = File.ReadAllLines(txtProxyListPath.Text);

// No need for the list
// List<string> list_lines = new List<string>(lines); 

Parallel.ForEach(lines, line =>
{
    //My Stuff
});

これにより、ループ内で行が並列に解析されます。Parallelクラスのより詳細で「参照指向」の紹介が必要な場合は、Parallel.ForEachに関するセクションを含むTPLに関するシリーズを作成しました。


9

大きなファイルの場合、次のコードを使用します(メモリの消費量が少なくなります)

Parallel.ForEach(File.ReadLines(txtProxyListPath.Text), line => {
    //Your stuff
});

2

これらのラインは私のために働いた。

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(lines , options, (item) =>
{
 //My Stuff
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.