TaskGroup : Maîtriser le parallélisme dynamique en Swift

Publié le · Mis à jour le · 21 min

Wlad
Wlad
Fondateur & Tech Lead Swift

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 :

TypeThrowingRésultats

withTaskGroup

Non

Collectés

withThrowingTaskGroup

Oui

Collectés

withDiscardingTaskGroup

Non

Ignorés

withThrowingDiscardingTaskGroup

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

AspectTaskGroupDiscardingTaskGroup

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

SituationType recommandé

Collecter des résultats

withTaskGroup

Tâches qui peuvent échouer

withThrowingTaskGroup

Fire-and-forget

withDiscardingTaskGroup

Serveur/boucle infinie

withDiscardingTaskGroup

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.

Ressources officielles