Au-delà d'/ pour l'I/O, .NET fournit la pour le — exécuter des calculs sur plusieurs cœurs. La distinction clé : / est pour la concurrence I/O (attentes non-bloquantes), tandis que , et PLINQ sont pour paralléliser le travail intensif en CPU.
Au-delà d'/ pour l'I/O, .NET fournit la pour le — exécuter des calculs sur plusieurs cœurs. La distinction clé : / est pour la concurrence I/O (attentes non-bloquantes), tandis que , et PLINQ sont pour paralléliser le travail intensif en CPU.
asyncawaitasyncawaitTask.RunParallelLa distinction cruciale : concurrence vs parallélisme
async/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 planifie le travail sur un thread du pool de threads — utilisez-le pour paralléliser les calculs liés au CPU (PAS pour l'I/O, où async/await suffit déjà sans threads supplémentaires).
// 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 et PLINQ (.AsParallel()) distribuent automatiquement le travail sur les cœurs — excellent pour le traitement très gourmand en CPU d'éléments indépendants. (Cela ne vaut la peine que pour du travail véritablement lié au CPU et de taille significative — il y a une surcharge.)
// 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
Comprendre les Tasks et le parallélisme au-delà d'async/await est une connaissance importante au niveau senior pour construire des applications C# performantes, et la distinction cruciale entre la concurrence I/O et le parallélisme CPU est l'insight clé — un point de confusion courant. async/await gère la concurrence liée à l'I/O (libération des threads lors des attentes) mais n'ajoute PAS de parallélisme CPU, tandis que le travail lié au CPU (calculs, traitement de données) bénéficie du parallélisme réel sur les cœurs via Task.Run (décharger le travail CPU sur les threads du pool), Parallel.For/ForEach et PLINQ (.AsParallel()).
Savoir quel outil s'adapte — async/await pour l'I/O, les outils TPL de parallélisme pour le travail lié au CPU — est essentiel pour l'optimisation efficace des performances, car utiliser le mauvais (par exemple s'attendre à ce qu'async accélère les calculs, ou créer des threads pour l'I/O qu'async gère efficacement) est inefficace.
Également important est de comprendre la sécurité des threads : le code parallèle accédant à un état partagé a besoin de synchronisation (lock, Interlocked pour les opérations atomiques, ou des collections thread-safe comme ConcurrentDictionary) pour éviter les conditions de course — une préoccupation critique de correction dans le code parallèle.
Comprendre la distinction I/O-vs-CPU, les outils de parallélisme (Task.Run, Parallel, PLINQ) et les exigences de sécurité des threads est précieux pour écrire du C# concurrent et parallèle correct et performant.
Étant donné que les applications modernes ont souvent besoin à la fois de concurrence I/O et de parallélisme CPU, et puisque choisir la bonne approche et gérer correctement la sécurité des threads sont ce qui rend le code parallèle efficace et correct, c'est une connaissance senior importante et fréquemment pertinente pour le développement C# sensible aux performances.