Computer >> 컴퓨터 >  >> 프로그래밍 >> C#

C# Foreach와 Parallel.ForEach의 차이점 완벽 비교

C# Foreach와 Parallel.ForEach의 핵심 차이점

C#의 foreach 루프는 단일 스레드에서 실행되며, 컬렉션의 각 항목을 순차적으로 하나씩 처리합니다. 반면 Parallel.ForEach 루프는 여러 스레드를 활용하여 작업을 병렬 방식으로 수행합니다. 즉, 이전 항목의 처리가 완료되기를 기다리지 않고 모든 항목을 동시에 순회할 수 있습니다.

Parallel.ForEach는 일반적인 foreach보다 실행 속도가 빠르다는 장점이 있습니다. Parallel.ForEach 루프를 사용하려면 System.Threading.Tasks 네임스페이스를 프로젝트에 추가해야 합니다.

예제 코드

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", "lepoard", "monkey", "kangaroo", "girafee", "hippo"
            };
            var stopWatch = Stopwatch.StartNew();
            foreach (string animal in animals){
                Console.WriteLine($"Fruit 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($"Fruit Name: {animal}, Thread Id={Thread.CurrentThread.ManagedThreadId}");
            });
            Console.WriteLine($"Parallel foreach loop execution time = {stopWatch2.Elapsed.TotalSeconds} seconds");
            Console.ReadLine();
        }
    }
}

실행 결과

위 코드를 실행하면 다음과 같은 결과가 출력됩니다.

Fruit Name: cat, Thread Id= 1
Fruit Name: rat, Thread Id= 1
Fruit Name: deer, Thread Id= 1
Fruit Name: elephant, Thread Id= 1
Fruit Name: lion, Thread Id= 1
Fruit Name: tiger, Thread Id= 1
Fruit Name: dog, Thread Id= 1
Fruit Name: pig, Thread Id= 1
Fruit Name: buffalo, Thread Id= 1
Fruit Name: rabbit, Thread Id= 1
Fruit Name: horse, Thread Id= 1
Fruit Name: cheetah, Thread Id= 1
Fruit Name: cow, Thread Id= 1
Fruit Name: goat, Thread Id= 1
Fruit Name: sheep, Thread Id= 1
Fruit Name: donkey, Thread Id= 1
Fruit Name: zebra, Thread Id= 1
Fruit Name: wolf, Thread Id= 1
Fruit Name: fox, Thread Id= 1
Fruit Name: lepoard, Thread Id= 1
Fruit Name: monkey, Thread Id= 1
Fruit Name: kangaroo, Thread Id= 1
Fruit Name: girafee, Thread Id= 1
Fruit Name: hippo, Thread Id= 1
foreach loop execution time = 0.0129221 seconds
Fruit Name: cat, Thread Id= 1
Fruit Name: rat, Thread Id= 1
Fruit Name: deer, Thread Id= 1
Fruit Name: elephant, Thread Id= 1
Fruit Name: lion, Thread Id= 1
Fruit Name: tiger, Thread Id= 1
Fruit Name: pig, Thread Id= 1
Fruit Name: buffalo, Thread Id= 1
Fruit Name: dog, Thread Id= 3
Fruit Name: sheep, Thread Id= 3
Fruit Name: donkey, Thread Id= 3
Fruit Name: rabbit, Thread Id= 1
Fruit Name: goat, Thread Id= 5
Fruit Name: fox, Thread Id= 5
Fruit Name: lepoard, Thread Id= 5
Fruit Name: cow, Thread Id= 4
Fruit Name: hippo, Thread Id= 4
Fruit Name: kangaroo, Thread Id= 9
Fruit Name: girafee, Thread Id= 6
Fruit Name: monkey, Thread Id= 5
Fruit Name: horse, Thread Id= 1
Fruit Name: cheetah, Thread Id= 1
Fruit Name: zebra, Thread Id= 3
Fruit 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의 실행 시간(0.0092988초)이 일반 foreach(0.0129221초)보다 짧아 더 나은 성능을 보여줍니다.

다만 Parallel.ForEach 사용 시 몇 가지 유의할 점이 있습니다. 항목의 처리 순서가 보장되지 않으므로 순서가 중요한 로직에는 적합하지 않으며, 여러 스레드가 공유 자원에 동시에 접근할 수 있으므로 스레드 안전성(thread safety)을 반드시 고려해야 합니다. 따라서 CPU 집약적이고 각 항목이 독립적으로 처리될 수 있는 대량의 작업에 Parallel.ForEach를 활용하는 것이 가장 효과적입니다.