Além de / para I/O, .NET fornece a para — executando computações em múltiplos núcleos. A distinção-chave: / é para concorrência de I/O (esperas não-bloqueantes), enquanto , e PLINQ são para paralelizar trabalho CPU-intensivo.
Além de / para I/O, .NET fornece a para — executando computações em múltiplos núcleos. A distinção-chave: / é para concorrência de I/O (esperas não-bloqueantes), enquanto , e PLINQ são para paralelizar trabalho CPU-intensivo.
asyncawaitasyncawaitTask.RunParallelasync/await → I/O-bound concurrency. Frees the thread during waits (DB, network).
Does NOT add CPU parallelism.
Parallelism → CPU-bound work spread across MULTIPLE CORES (computation, processing).
Use Task.Run, Parallel.For/ForEach, PLINQ.
// run a CPU-intensive computation on a thread pool thread (don't block the caller)
int result = await Task.Run(() => ExpensiveComputation());
// run multiple in parallel and combine
var tasks = items.Select(item => Task.Run(() => Process(item)));
var results = await Task.WhenAll(tasks); // wait for all
Task.Run agenda trabalho em uma thread de thread pool — use-a para paralelizar computação CPU-bound (NÃO para I/O, onde async/await já é suficiente sem threads extras).
// Parallel.For/ForEach — process a collection across cores
Parallel.ForEach(items, item => Process(item)); // automatically uses multiple cores
Parallel.For(0, 1000, i => Compute(i));
// PLINQ — parallel LINQ
var results = data.AsParallel().Where(x => IsValid(x)).Select(Transform).ToList();
Parallel.For/ForEach e PLINQ (.AsParallel()) distribuem automaticamente trabalho sobre núcleos — excelente para processamento CPU-pesado de itens independentes. (Só vale a pena para trabalho genuinamente CPU-bound e de tamanho considerável — há overhead.)
// parallel code accessing SHARED state needs synchronization or thread-safe types
lock (_lock) { _counter++; } // lock for mutual exclusion
Interlocked.Increment(ref _counter); // lock-free atomic
var dict = new ConcurrentDictionary<string, int>(); // thread-safe collection
Entender Tasks e paralelismo além de async/await é conhecimento importante de nível sênior para construir aplicações C# performáticas, e a distinção crucial entre concorrência de I/O e paralelismo CPU é o insight-chave — um ponto comum de confusão. async/await lida com concorrência I/O-bound (liberando threads durante esperas) mas não adiciona paralelismo CPU, enquanto trabalho CPU-bound (computações, processamento de dados) se beneficia de paralelismo real entre núcleos via Task.Run (descarregando trabalho CPU para threads de thread pool), Parallel.For/ForEach e PLINQ (.AsParallel()).
Saber qual ferramenta se encaixa — async/await para I/O, as ferramentas TPL para trabalho CPU-bound — é essencial para otimização de performance efetiva, já que usar a ferramenta errada (por exemplo, esperar que async acelere computação, ou criar threads para I/O que async lida eficientemente) é ineficaz.
Igualmente importante é entender thread safety: código paralelo acessando estado compartilhado precisa sincronização (lock, Interlocked para operações atômicas, ou coleções thread-safe como ConcurrentDictionary) para evitar race conditions — uma preocupação crítica de corretude em código paralelo.
Entender a distinção I/O-vs-CPU, as ferramentas de paralelismo (Task.Run, Parallel, PLINQ) e os requisitos de thread-safety é valioso para escrever C# concorrente e paralelo correto e performático.
Como aplicações modernas frequentemente precisam tanto de concorrência I/O quanto paralelismo CPU, e como escolher a abordagem correta e lidar com thread safety corretamente é o que torna código paralelo efetivo e correto, este é conhecimento sênior importante e frequentemente relevante para desenvolvimento C# sensível a performance.