Más allá de / para I/O, .NET proporciona la para — ejecutar cálculos en múltiples núcleos. La distinción clave: / es para concurrencia de I/O (esperas no bloqueantes), mientras que , y PLINQ son para paralelizar trabajo ligado a CPU.
Más allá de / para I/O, .NET proporciona la para — ejecutar cálculos en múltiples núcleos. La distinción clave: / es para concurrencia de I/O (esperas no bloqueantes), mientras que , y PLINQ son para paralelizar trabajo ligado a CPU.
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 programa trabajo en un hilo del thread pool — úsalo para paralelizar cálculos ligados a CPU (NO para I/O, donde async/await ya es suficiente sin hilos extra).
// 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 y PLINQ (.AsParallel()) distribuyen automáticamente el trabajo entre núcleos — excelente para procesamiento intensivo de CPU de elementos independientes. (Solo vale la pena para trabajo genuinamente ligado a CPU y de tamaño considerable — hay sobrecarga.)
// 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 y paralelismo más allá de async/await es conocimiento importante de nivel senior para construir aplicaciones C# performantes, y la distinción crucial entre concurrencia de I/O y paralelismo de CPU es el conocimiento clave — un punto de confusión común. async/await maneja concurrencia ligada a I/O (liberando hilos durante esperas) pero no añade paralelismo de CPU, mientras que el trabajo ligado a CPU (cálculos, procesamiento de datos) se beneficia del paralelismo real entre núcleos mediante Task.Run (delegando trabajo de CPU a hilos del thread pool), Parallel.For/ForEach y PLINQ (.AsParallel()).
Saber qué herramienta encaja — async/await para I/O, las herramientas de paralelismo de TPL para trabajo ligado a CPU — es esencial para optimización de rendimiento efectiva, ya que usar la herramienta equivocada (p. ej., esperar que async acelere cálculos, o crear hilos para I/O que async maneja eficientemente) es inefectivo.
Igualmente importante es entender seguridad en hilos: código paralelo que accede a estado compartido necesita sincronización (lock, Interlocked para operaciones atómicas, o colecciones thread-safe como ConcurrentDictionary) para evitar condiciones de carrera — una preocupación de corrección crítica en código paralelo.
Entender la distinción I/O-vs-CPU, las herramientas de paralelismo (Task.Run, Parallel, PLINQ) y los requisitos de seguridad en hilos es valioso para escribir C# concurrente y paralelo correcto y performante.
Ya que las aplicaciones modernas a menudo necesitan concurrencia de I/O y paralelismo de CPU, y ya que elegir el enfoque correcto y manejar la seguridad en hilos correctamente es lo que hace que el código paralelo sea efectivo y correcto, este es conocimiento senior importante y frecuentemente relevante para desarrollo C# sensible al rendimiento.