C#
 Computer >> コンピューター >  >> プログラミング >> C#

C#のforeachとParallel.ForEachの違いとは?並列処理による高速化を解説

C#におけるforeachとParallel.ForEachの基本的な違い

C#の通常のforeachループは、単一のスレッド上で動作し、要素を1つずつ順番に(逐次的に)処理していきます。一方、Parallel.ForEachは複数のスレッド上で動作し、各要素を並列に処理します。つまり、前の要素の処理完了を待たずに、すべての項目に対して同時にループ処理を行うことができます。

そのため、Parallel.ForEachは通常のforeachよりも高速に実行できるのが大きな特徴です。Parallel.ForEachを使用するには、System.Threading.Tasks名前空間をインポートする必要があります。

サンプルコード

以下のコードでは、動物のリストに対して通常のforeachParallel.ForEachの両方を実行し、それぞれの実行時間とスレッドIDを計測・表示しています。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace DemoApplication {
   class Demo {
      static void Main(string[] args) {
         var animals = new List<string> {
            "cat", "rat", "deer", "elephant", "lion", "tiger", "dog", "pig",
            "buffalo", "rabbit", "horse", "cheetah", "cow", "goat", "sheep",
            "donkey", "zebra", "wolf", "fox", "leopard", "monkey",
            "kangaroo", "giraffe", "hippo"
         };

         var stopWatch = Stopwatch.StartNew();
         foreach (string animal in animals) {
            Console.WriteLine($"Animal Name: {animal}, Thread Id={Thread.CurrentThread.ManagedThreadId}");
         }
         Console.WriteLine($"foreach loop execution time = {stopWatch.Elapsed.TotalSeconds} seconds");

         var stopWatch2 = Stopwatch.StartNew();
         Parallel.ForEach(animals, animal => {
            Console.WriteLine($"Animal Name: {animal}, Thread Id={Thread.CurrentThread.ManagedThreadId}");
         });
         Console.WriteLine($"Parallel foreach loop execution time = {stopWatch2.Elapsed.TotalSeconds} seconds");

         Console.ReadLine();
      }
   }
}

実行結果

上記コードの実行結果は以下のとおりです。

Animal Name: cat, Thread Id= 1
Animal Name: rat, Thread Id= 1
Animal Name: deer, Thread Id= 1
Animal Name: elephant, Thread Id= 1
Animal Name: lion, Thread Id= 1
Animal Name: tiger, Thread Id= 1
Animal Name: dog, Thread Id= 1
Animal Name: pig, Thread Id= 1
Animal Name: buffalo, Thread Id= 1
Animal Name: rabbit, Thread Id= 1
Animal Name: horse, Thread Id= 1
Animal Name: cheetah, Thread Id= 1
Animal Name: cow, Thread Id= 1
Animal Name: goat, Thread Id= 1
Animal Name: sheep, Thread Id= 1
Animal Name: donkey, Thread Id= 1
Animal Name: zebra, Thread Id= 1
Animal Name: wolf, Thread Id= 1
Animal Name: fox, Thread Id= 1
Animal Name: leopard, Thread Id= 1
Animal Name: monkey, Thread Id= 1
Animal Name: kangaroo, Thread Id= 1
Animal Name: giraffe, Thread Id= 1
Animal Name: hippo, Thread Id= 1
foreach loop execution time = 0.0129221 seconds

Animal Name: cat, Thread Id= 1
Animal Name: rat, Thread Id= 1
Animal Name: deer, Thread Id= 1
Animal Name: elephant, Thread Id= 1
Animal Name: lion, Thread Id= 1
Animal Name: tiger, Thread Id= 1
Animal Name: pig, Thread Id= 1
Animal Name: buffalo, Thread Id= 1
Animal Name: dog, Thread Id= 3
Animal Name: sheep, Thread Id= 3
Animal Name: donkey, Thread Id= 3
Animal Name: rabbit, Thread Id= 1
Animal Name: goat, Thread Id= 5
Animal Name: fox, Thread Id= 5
Animal Name: leopard, Thread Id= 5
Animal Name: cow, Thread Id= 4
Animal Name: hippo, Thread Id= 4
Animal Name: kangaroo, Thread Id= 9
Animal Name: giraffe, Thread Id= 6
Animal Name: monkey, Thread Id= 5
Animal Name: horse, Thread Id= 1
Animal Name: cheetah, Thread Id= 1
Animal Name: zebra, Thread Id= 3
Animal Name: wolf, Thread Id= 3
Parallel foreach loop execution time = 0.0092988 seconds

結果からわかること

実行結果を見ると、通常のforeachではすべての処理がスレッドID「1」のみで実行されているのに対し、Parallel.ForEachではスレッドIDが「1」「3」「4」「5」「6」「9」など複数のスレッドに分散していることが確認できます。これは、Parallel.ForEachが実際にマルチスレッドで並列処理を行っている証拠です。

また、この例のように処理が軽い場合でも実行時間に差が現れており、より重い処理(ファイルI/Oや画像処理など)を大量のデータに対して行う場合には、Parallel.ForEachによる高速化効果がさらに顕著になります。

使い分けのポイント

  • foreach: 処理順序を保証したい場合や、軽量な処理、共有リソースへの安全なアクセスが必要な場合に適しています。
  • Parallel.ForEach: 各要素の処理が互いに独立しており、順序に依存しない重い処理を大量のデータに対して実行する場合に適しています。

なお、Parallel.ForEachは要素の処理順序が保証されないため、順序が重要なロジックでは使用しないよう注意しましょう。

  1. DirectX11とDirectX12の違いを徹底解説!ゲーマーが知っておくべきポイント

    DirectXは、ソフトウェアがマルチメディアコンテンツを描画し、グラフィックハードウェアと通信するために使用されるAPI(アプリケーションプログラミングインターフェース)のコレクションです。DirectXの主要な構成要素であるDirect3Dは、ソフトウェアとグラフィックスハードウェア間の通信を担っています。ハードウェアは製品ごとに異なるため、標準化された関数や呼び出しのライブラリを通じてグラフィックカードと通信することで、ゲーム開発を大幅にスピードアップできます。これは「ハードウェア抽象化」と呼ばれ、APIの最も重要な役割となっています。車に例えてみましょう。1台の車の運転ができれば、ほぼ

  2. C#の配列とリスト(List)の違いとは?特徴と基本的な使い方を解説

    C#における配列(Array)とリスト(List<T>)は、どちらも複数のデータをまとめて扱うためのコレクションですが、その性質には重要な違いがあります。 配列とリストの主な違い 配列は、生成時にサイズが固定される、同じ型の要素を順番に格納するコレクションです。一度作成した後は要素数を変更できません。 一方、Listはジェネリックコレクションであり、要素の追加や削除に応じてサイズが自動的に拡張・縮小します。この柔軟性が最大の特徴です。 項目配列List<T> サイズ固定可変(動的) 要素の追加不可(再作成が必要)Addメソッドで可能 宣言方法型[] 変数名Lis