I/O를 위한 async/await를 넘어서, .NET은 CPU 바운드 병렬성을 위한 **TPL(Task Parallel Library)**을 제공합니다 — 여러 코어에 걸쳐 계산을 실행합니다. 핵심 구분: /는 I/O 동시성(비차단 대기)을 위한 것이고, , , PLINQ는 CPU 집약적 작업을 병렬화하기 위한 것입니다.
asyncawaitTask.RunParallelasync/await → I/O 바운드 동시성. 대기 중 스레드를 풀어 줌(DB, 네트워크).
CPU 병렬성을 추가하지 않음.
병렬성 → CPU 바운드 작업을 여러 코어에 분산(계산, 처리).
Task.Run, Parallel.For/ForEach, PLINQ 사용.
// CPU 집약적 계산을 스레드 풀 스레드에서 실행(호출자를 차단하지 않음)
int result = await Task.Run(() => ExpensiveComputation());
// 여러 개를 병렬로 실행하고 결합
var tasks = items.Select(item => Task.Run(() => Process(item)));
var results = await Task.WhenAll(tasks); // 모두 대기
Task.Run은 작업을 스레드 풀 스레드에 스케줄링합니다 — CPU 바운드 계산을 병렬화하는 데 사용하세요(I/O에는 쓰지 마세요, 거기서는 async/await가 추가 스레드 없이 이미 충분함).
// Parallel.For/ForEach — 컬렉션을 코어에 걸쳐 처리
Parallel.ForEach(items, item => Process(item)); // 자동으로 여러 코어 사용
Parallel.For(0, 1000, i => Compute(i));
// PLINQ — 병렬 LINQ
var results = data.AsParallel().Where(x => IsValid(x)).Select(Transform).ToList();
Parallel.For/ForEach와 PLINQ(.AsParallel())는 작업을 코어에 자동으로 분산합니다 — 독립적인 항목들의 CPU 집약적 처리에 좋습니다. (진정으로 CPU 바운드이고 상당한 작업에만 가치가 있습니다 — 오버헤드가 있음.)
// 공유 상태에 접근하는 병렬 코드는 동기화나 스레드 안전 타입이 필요
lock (_lock) { _counter++; } // 상호 배제를 위한 lock
Interlocked.Increment(ref _counter); // 락 없는 원자적 연산
var dict = new ConcurrentDictionary<string, int>(); // 스레드 안전 컬렉션
async/await를 넘어서 Task와 병렬성을 이해하는 것은 성능 좋은 C# 애플리케이션을 구축하기 위한 중요한 시니어 수준 지식이며, I/O 동시성과 CPU 병렬성 사이의 결정적 구분이 핵심 통찰입니다 — 흔한 혼동 지점입니다. async/await는 I/O 바운드 동시성(대기 중 스레드를 풀어 줌)을 처리하지만 CPU 병렬성을 추가하지 않으며, 반면 CPU 바운드 작업(계산, 데이터 처리)은 Task.Run(CPU 작업을 스레드 풀 스레드로 넘김), Parallel.For/ForEach, PLINQ(.AsParallel())를 통한 실제 코어 간 병렬성에서 이득을 봅니다.
어떤 도구가 적합한지 — I/O에는 async/await, CPU 바운드 작업에는 TPL 병렬성 도구 — 를 아는 것은 효과적인 성능 최적화에 필수적입니다. 잘못된 것을 쓰는 것(예: async가 계산을 빠르게 할 것으로 기대하거나, async가 효율적으로 처리하는 I/O를 위해 스레드를 띄우는 것)은 비효과적이기 때문입니다.
마찬가지로 중요한 것은 스레드 안전성을 이해하는 것입니다: 공유 상태에 접근하는 병렬 코드는 경쟁 조건을 피하기 위해 동기화(lock, 원자적 연산을 위한 Interlocked, 또는 ConcurrentDictionary 같은 스레드 안전 컬렉션)가 필요합니다 — 병렬 코드에서 결정적인 정확성 문제입니다.
I/O vs CPU 구분, 병렬성 도구(Task.Run, Parallel, PLINQ), 스레드 안전성 요구 사항을 이해하는 것은 올바르고 성능 좋은 동시/병렬 C#을 작성하는 데 가치가 있습니다.
현대 애플리케이션은 흔히 I/O 동시성과 CPU 병렬성을 모두 필요로 하고, 올바른 접근법을 선택하고 스레드 안전성을 올바르게 처리하는 것이 병렬 코드를 효과적이고 올바르게 만드는 것이므로, 이는 성능에 민감한 C# 개발을 위한 중요하고 자주 관련되는 시니어 지식입니다.