Information sur l'article
Categorie: csharp, channels, concurrency, async, pipelines
Mise à jour: 2025-08-09
Temps de lecture: 9 min

C# Channels : construire un pipeline async clair et efficace
Mise à jour: 2025-08-09
Pourquoi utiliser les Channels ?
System.Threading.Channels fournit une file asynchrone hautes performances pour relier des producteurs et des consommateurs avec backpressure intégré.
Exemple concret : traiter des commandes en parallèle
Objectif: ingérer des commandes, les traiter en parallèle (limité), et s’arrêter propreement (annulation).
Points clés
- BoundedChannel = backpressure: si plein, WriteAsync attend. Idéal pour protéger une ressource (DB, API).
- ReadAllAsync(ct) = boucle asynchrone propre qui s’arrête quand le writer est Completed (et le canal vidé).
- SingleWriter/SingleReader optimisent les verrous internes si c’est votre cas.
- writer.Complete() signale la fin; tous les consommateurs finissent naturellement.
Variante : pipeline en 2 étapes (validation -> persist)
Bonnes pratiques
- Toujours consommer via ReadAllAsync dans un while/await foreach (et non TryRead en boucle occupée).
- Annulation: passez un CancellationToken à ReadAllAsync/WriteAsync; ne pas oublier Complete() côté writer.
- Dimensionner la capacité selon la latence des consommateurs (pointe × latence), et mesurer.
- Préférer Channels à BlockingCollection en contexte async; évitez les locks inutiles.
Comparaison : Channels vs Parallel.ForEach vs ConcurrentQueue
- Channels: parfaits pour des flux asynchrones (producteur continu), backpressure natif, arrêt propre via Complete(), "await foreach" lisible.
- Parallel.ForEach/ForEachAsync: pratique pour traiter un ensemble fini connu d’avance, limiter le parallélisme CPU, mais pas de sémantique de file ni de backpressure dynamique.
- ConcurrentQueue: thread-safe mais pas de backpressure ni de "signal" intégré; il faut ajouter sémaphores/événements et gérer l’arrêt/annulation manuellement.
Exemple Parallel.ForEachAsync (sans backpressure)
Exemple ConcurrentQueue + SemaphoreSlim (gestion manuelle)
Quand choisir quoi ?
- Flux continu, besoin de backpressure et d’un arrêt propre: Channels.
- Batch fini connu d’avance, parallélisme simple: Parallel.ForEach/ForEachAsync.
- Interop ou héritage existant avec queues: ConcurrentQueue (+ sémaphores/événements) mais privilégier Channels en nouveau code async.
Conclusion
Merci d’avoir lu cet article. Si vous avez des questions, envie d’améliorer l’exemple ou de suggérer un sujet, contactez-moi: je serai ravi d’échanger.
Sommaire
- Pourquoi utiliser les Channels ?
- Exemple concret : traiter des commandes en parallèle
- Points clés
- Variante : pipeline en 2 étapes (validation -> persist)
- Bonnes pratiques
- Comparaison : Channels vs Parallel.ForEach vs ConcurrentQueue
- Exemple Parallel.ForEachAsync (sans backpressure)
- Exemple ConcurrentQueue + SemaphoreSlim (gestion manuelle)
- Quand choisir quoi ?
- Conclusion