TaskGroup : Maîtriser le parallélisme dynamique en Swift
Publié le · Mis à jour le · 21 min
TaskGroup est l'API de choix pour exécuter un nombre arbitraire de tâches en parallèle et collecter leurs résultats. Contrairement à async let qui nécessite de connaître le nombre de tâches à la compilation, TaskGroup permet de créer des tâches dynamiquement à l'exécution. Ce guide couvre tout, des fondamentaux aux patterns avancés avec DiscardingTaskGroup.
Pourquoi TaskGroup ?
async let est parfait quand vous connaissez le nombre exact de tâches :
Mais que faire si vous devez télécharger 1000 images ? Écrire 1000 async let n'est pas envisageable. C'est là que TaskGroup intervient :
Les variantes de TaskGroup
Swift propose quatre types de task groups :
| Type | Throwing | Résultats |
|---|---|---|
| Non | Collectés |
| Oui | Collectés |
| Non | Ignorés |
| Oui | Ignorés |
Syntaxe de base
Création et ajout de tâches
withTaskGroup de base
Priorité des tâches
Chaque tâche peut avoir sa propre priorité :
addTaskUnlessCancelled
Pour éviter d'ajouter des tâches si le groupe est déjà annulé :
Collecte des résultats
Itération avec for await
La méthode la plus courante pour collecter les résultats :
Important : l'ordre des résultats n'est PAS garanti. Les tâches se terminent dans n'importe quel ordre selon leur durée.
Préserver l'ordre avec des tuples
Pour maintenir l'ordre original, incluez l'index :
Utiliser reduce
Pour agréger les résultats directement :
Utiliser next()
Pour un contrôle fin sur la consommation des résultats :
waitForAll()
Pour attendre toutes les tâches sans collecter les résultats :
Gestion des erreurs avec ThrowingTaskGroup
Comportement par défaut : fail-fast
Avec withThrowingTaskGroup, la première erreur est propagée et le groupe est annulé :
Collect-all : continuer malgré les erreurs
Pour collecter tous les résultats même si certaines tâches échouent :
Pattern dashboard : sections indépendantes
Annulation
cancelAll()
Pour annuler toutes les tâches restantes :
isCancelled et checkCancellation
Les tâches doivent vérifier l'annulation coopérativement :
Annulation automatique à la sortie
Le groupe attend toujours toutes les tâches avant de retourner, même après cancelAll() :
DiscardingTaskGroup (Swift 5.9+)
Le problème avec TaskGroup classique
Avec un TaskGroup standard, si vous n'appelez pas next() ou n'itérez pas sur le groupe, les tâches terminées restent en mémoire :
Solution : DiscardingTaskGroup
DiscardingTaskGroup nettoie automatiquement les tâches terminées :
Cas d'usage idéaux
DiscardingTaskGroup est parfait pour :
- Serveurs HTTP/WebSocket : boucle infinie de connexions
- File watchers : surveillance continue de fichiers
- Event listeners : traitement d'événements en continu
- Background workers : tâches sans résultat à collecter
Différences avec TaskGroup
| Aspect | TaskGroup | DiscardingTaskGroup |
|---|---|---|
Résultats | Collectés via next()/for await | Ignorés immédiatement |
Mémoire | Tâches gardées jusqu'à consommation | Libérées dès terminées |
AsyncSequence | Oui | Non |
next() | Disponible | Non disponible |
Cas d'usage | Collecter des résultats | Fire-and-forget, serveurs |
Patterns avancés
Limiter la concurrence
TaskGroup ne limite pas le nombre de tâches concurrentes par défaut. Voici comment le faire :
Timeout global
Race : premier arrivé, premier servi
Retry avec parallélisme
Types hétérogènes avec enum
Pour des tâches qui retournent des types différents :
Bonnes pratiques
1. Toujours consommer les résultats ou utiliser DiscardingTaskGroup
2. Gérer l'annulation dans les tâches
3. Éviter les captures fortes de self
4. Utiliser le bon type de groupe
| Situation | Type recommandé |
|---|---|
Collecter des résultats |
|
Tâches qui peuvent échouer |
|
Fire-and-forget |
|
Serveur/boucle infinie |
|
Pièges courants
1. Oublier que l'ordre n'est pas garanti
2. Ne pas gérer les erreurs correctement
3. Créer trop de tâches d'un coup
Pour aller plus loin
TaskGroup est l'outil essentiel pour le parallélisme dynamique en Swift. Combiné avec async let pour les cas simples et DiscardingTaskGroup pour les serveurs, vous avez tout ce qu'il faut pour écrire du code concurrent performant et sûr.