DispatchQueue : qu'est-ce que c'est, file d'attente GCD et bases du multithreading

Auteur : IT Sectr Publié le : 2026-03-16 Temps de lecture : 8 min

DispatchQueue est une file d'attente fondamentale de Grand Central Dispatch (GCD) pour gérer les tâches asynchrones sur iOS et macOS. Selon la Apple Developer Documentation, 2026, DispatchQueue abstrait la gestion des threads du développeur grâce à des files d'attente sérialisées et concurrentes. GCD distribue automatiquement les tâches sur le pool de threads système, éliminant le besoin de créer et de détruire manuellement des threads.

Points clés

  • DispatchQueue est l'abstraction principale de GCD pour l'exécution de code asynchrone sur iOS
  • File d'attente sérialisée exécute les tâches strictement en séquence, éliminant les conditions de concurrence
  • File d'attente concurrente exécute plusieurs tâches en parallèle via le pool de threads système
  • QoS définit la priorité de la tâche — de userInteractive à background
  • DispatchQueue.main est la seule file d'attente pour mettre à jour UIKit sur le thread principal

Qu'est-ce que DispatchQueue et Grand Central Dispatch

DispatchQueue est un objet du framework Grand Central Dispatch (GCD) qui gère l'exécution des tâches dans des files d'attente de threads système ou personnalisées. Grand Central Dispatch est une bibliothèque bas niveau d'Apple, disponible depuis iOS 4 et macOS 10.6, qui abstrait complètement la gestion des threads du développeur. GCD utilise le pool de threads du système d'exploitation et adapte automatiquement le nombre de threads en fonction de la charge de l'appareil.

Le développeur n'a pas besoin de créer et de détruire manuellement des threads — GCD s'occupe de cette tâche, offrant une API simple via DispatchQueue. Une tâche sous forme de closure est envoyée à une file d'attente via les méthodes sync ou async. Dans le premier cas, le thread appelant est bloqué jusqu'à la fin de la tâche ; dans le second, l'exécution continue immédiatement.

Selon Apple (2026), GCD utilise un pool de threads système qui s'adapte au nombre de cœurs et à la charge actuelle du processeur. Une file d'attente concurrente ne crée pas un nouveau thread pour chaque tâche — GCD réutilise les threads du pool, minimisant les frais généraux de création de threads.

Architecture de GCD

Grand Central Dispatch se compose de trois composants clés : les files d'attente (DispatchQueue), les groupes (DispatchGroup) et les sémaphores (DispatchSemaphore). La file d'attente est l'élément principal qui accepte les tâches sous forme de blocs de code. DispatchGroup synchronise l'exécution de plusieurs tâches, tandis que DispatchSemaphore limite l'accès à une ressource partagée à un nombre spécifique de threads.

Chaque file d'attente GCD est associée à une classe QoS (Quality of Service) spécifique, qui informe le système de l'importance de la tâche. Le système utilise la QoS pour répartir le temps CPU entre les files d'attente, en priorisant les tâches les plus critiques — comme la mise à jour de l'UI ou le traitement des touches utilisateur.

Files d'attente sérialisées et concurrentes : comparaison

Une file d'attente sérialisée exécute les tâches strictement en séquence, l'une après l'autre. Si trois tâches sont placées dans une file d'attente sérialisée, la seconde ne commence qu'après la fin complète de la première. Les files d'attente sérialisées sont utilisées pour synchroniser l'accès aux ressources partagées — par exemple, un tableau modifié depuis plusieurs parties du code.

Une file d'attente concurrente exécute plusieurs tâches simultanément, en les répartissant sur les threads disponibles du pool système. Les tâches dans une file d'attente concurrente démarrent dans l'ordre FIFO, mais se terminent dans un ordre arbitraire si leurs temps d'exécution diffèrent. Une file d'attente concurrente ne garantit pas l'ordre de fin — seulement l'ordre de démarrage.

ParamètreFile sérialiséeFile concurrente
Ordre d'exécutionStrictement séquentielParallèle
Nombre de threadsUnPlusieurs du pool GCD
ApplicationProtection des ressources partagéesCalculs indépendants
File principaleOui (thread principal)Non
Risque d'interblocageÉlevé lors du sync sur la même fileFaible

Quand choisir une file d'attente sérialisée

Une file d'attente sérialisée est idéale pour les tâches qui modifient un état partagé — écrire dans un fichier, mettre à jour un modèle de données ou travailler avec Core Data. L'utilisation d'une file d'attente sérialisée garantit que deux parties du code ne modifient pas les mêmes données simultanément, éliminant les conditions de concurrence sans verrous supplémentaires.

Quand choisir une file d'attente concurrente

Une file d'attente concurrente convient aux tâches qui ne dépendent pas les unes des autres : charger plusieurs images, requêtes réseau parallèles ou traitement par lots de données. GCD décide automatiquement du nombre de tâches à exécuter simultanément en fonction du nombre de cœurs du processeur et de la charge actuelle du système.

Quality of Service : priorités d'exécution des tâches

QoS (Quality of Service) est un mécanisme de GCD qui informe le système d'exploitation de l'importance et de l'urgence d'une tâche. Le système utilise la QoS pour l'ordonnancement des threads : les tâches avec une QoS plus élevée reçoivent plus de temps CPU et démarrent plus tôt. La valeur de QoS est transmise lors de la création d'une file d'attente ou de l'envoi d'une tâche spécifique.

GCD propose cinq classes de QoS disponibles. .userInteractive — la priorité la plus élevée pour les tâches liées à l'UI. .userInitiated — pour les tâches initiées par l'utilisateur. .utility — pour les tâches d'arrière-plan qui affichent la progression. .background — pour les tâches invisibles pour l'utilisateur. .default — un niveau intermédiaire entre userInitiated et utility, utilisé par défaut.

Selon Apple (2026), une sélection incorrecte de la QoS est l'une des causes courantes de problèmes de performance. Exécuter un téléchargement en arrière-plan avec une QoS .userInteractive consomme les ressources de l'UI, provoquant des micro-ralentissements dans les animations. Il est recommandé de choisir la QoS la plus basse qui offre toujours un temps d'exécution acceptable.

Exemple d'utilisation de la QoS

Lors du chargement d'une image pour un affichage immédiat, utilisez .userInitiated — l'utilisateur attend le résultat. Pour le préchargement de l'écran suivant, .utility est suffisant. La synchronisation en arrière-plan avec le serveur s'effectue avec .background, minimisant l'impact sur les tâches actives.

DispatchGroup et sémaphores : synchronisation des tâches

DispatchGroup permet de suivre l'achèvement d'un groupe de tâches. Lorsque toutes les tâches du groupe sont terminées, GCD appelle un gestionnaire notify sur la file d'attente spécifiée. C'est particulièrement utile lors du chargement de plusieurs ressources indépendantes — données de profil, liste d'amis et paramètres — où l'interface doit être mise à jour seulement après la réception de toutes les données.

DispatchGroup prend en charge un appel synchrone wait(), qui bloque le thread actuel jusqu'à ce que toutes les tâches soient terminées. C'est pratique lorsque le code ne peut pas continuer sans les résultats du groupe. La variante asynchrone notify() appelle une closure sur la file d'attente spécifiée après l'achèvement de toutes les tâches, sans bloquer le thread appelant.

DispatchSemaphore pour limiter le parallélisme

DispatchSemaphore contrôle l'accès à une ressource en limitant le nombre d'accès simultanés. Un sémaphore avec une valeur initiale de 3 permet au maximum trois tâches parallèles. L'appel à wait() décrémente le compteur, signal() l'incrémente. Si le compteur atteint zéro, le thread se bloque jusqu'à ce qu'une ressource soit disponible.

Exemples de code avec DispatchQueue en Swift

Examinons trois exemples pratiques d'utilisation de DispatchQueue en Swift. Le premier illustre un appel async basique avec retour au thread principal, le deuxième montre la synchronisation via une file d'attente sérialisée, et le troisième utilise DispatchGroup pour des requêtes parallèles.

Appel async basique avec retour sur main

DispatchQueue.main est la file d'attente sérialisée du thread principal, destinée exclusivement aux opérations d'UI. Utilisez-la toujours pour mettre à jour l'interface après avoir terminé un travail en arrière-plan.

swift
let queue = DispatchQueue.global(qos: .userInitiated)
queue.async {
    let data = self.fetchData()
    DispatchQueue.main.async {
        self.updateUI(with: data)
    }
}

File d'attente sérialisée pour protéger une ressource partagée

Créer une file d'attente sérialisée personnalisée avec un identifiant unique synchronise l'accès à un tableau mutable. Toutes les opérations de lecture et d'écriture passent par une seule file d'attente, éliminant les conditions de concurrence.

swift
let serialQueue = DispatchQueue(label: "com.app.items")
var items: [Int] = []

serialQueue.async {
    items.append(1)
}
serialQueue.async {
    let last = items.last
    DispatchQueue.main.async {
        print("Last item: \(last)")
    }
}

DispatchGroup pour les requêtes parallèles

DispatchGroup permet de lancer plusieurs tâches sur une file d'attente concurrente et de recevoir une notification lorsque toutes sont terminées. C'est utile lors du chargement de données pour un écran de profil.

swift
let group = DispatchGroup()
let worker = DispatchQueue.global()

worker.async(group: group) { self.loadProfile() }
worker.async(group: group) { self.loadFriends() }
worker.async(group: group) { self.loadSettings() }

group.notify(queue: DispatchQueue.main) {
    self.showCompleteUI()
}

Erreurs courantes lors de l'utilisation de DispatchQueue

L'interblocage lors d'un appel sync sur une file d'attente sérialisée est l'erreur la plus courante. Si une tâche sur une file d'attente sérialisée appelle queue.sync sur la même file, le thread se bloque indéfiniment. La file attend la fin de la tâche en cours, et la tâche attend la fin de l'appel sync — un blocage mutuel classique.

Mise à jour de l'UI depuis un thread d'arrière-plan

Toutes les opérations avec UIKit doivent être effectuées sur le thread principal. Xcode détecte ces erreurs en mode Debug via le Main Thread Checker. Dans les versions Release, elles entraînent un comportement imprévisible : les animations ne démarrent pas, l'UI ne se met pas à jour, et des plantages peuvent survenir.

Création excessive de files d'attente personnalisées

Créer des centaines de files d'attente personnalisées au lieu d'utiliser des files globales est un antimotif. Chaque file d'attente consomme des ressources système. Pour la plupart des tâches, les files d'attente concurrentes globales avec différents niveaux de QoS et une ou deux files sérialisées pour synchroniser les données partagées sont suffisantes.

Ignorer autoreleasepool dans les boucles

Lors de l'exécution de tâches de boucle gourmandes en ressources sur une file d'attente d'arrière-plan sans autoreleasepool, la mémoire augmente jusqu'à la fin de toute la boucle. ARC ne libère les objets qu'à la sortie du pool d'autorelease. Enveloppez les itérations de boucle dans autoreleasepool { } pour une libération mémoire opportune.

Foire aux questions

Quelle est la différence entre DispatchQueue et OperationQueue ?

OperationQueue est construite au-dessus de GCD mais fournit une API de plus haut niveau avec des dépendances d'opérations, KVO et la prise en charge de l'annulation. DispatchQueue est une file d'attente bas niveau pour les tâches async simples sans gestion de dépendances.

Peut-on forcer l'arrêt d'une tâche dans DispatchQueue ?

GCD ne prend pas en charge l'arrêt d'une tâche en cours d'exécution. La méthode suspend() ne suspend que les nouvelles tâches ; la tâche en cours s'exécute jusqu'à la fin. L'annulation nécessite une vérification manuelle d'un indicateur dans le code de la tâche.

Quelle QoS choisir pour une requête réseau ?

Pour une requête principale avec affichage immédiat du résultat — .userInitiated. Pour le préchargement de données — .utility. Pour la synchronisation en arrière-plan — .background.

Combien de threads une file d'attente concurrente utilise-t-elle ?

GCD ne fixe pas le nombre de threads. Le pool de threads s'adapte dynamiquement sous charge, en tenant compte des cœurs du processeur, de la charge actuelle et de la QoS de chaque tâche. Le nombre maximum est limité par le système.

Pourquoi DispatchQueue.main est-il obligatoire pour UIKit ?

UIKit n'est pas thread-safe — toutes ses classes doivent être appelées uniquement depuis le thread principal. La violation entraîne un comportement imprévisible, des mises à jour manquées et des plantages en Production.

Résumé

  • DispatchQueue est l'outil principal de Grand Central Dispatch pour les tâches asynchrones sur iOS et macOS
  • File d'attente sérialisée exécute les tâches séquentiellement, éliminant les conditions de concurrence sans verrous
  • File d'attente concurrente exécute les tâches en parallèle via le pool de threads système
  • QoS détermine la priorité de la tâche — de userInteractive à background
  • DispatchGroup synchronise plusieurs tâches parallèles avec notify sur le thread principal
  • L'interblocage lors d'un sync sur une file sérialisée occupée est une erreur critique nécessitant de l'attention
  • Le thread principal est obligatoire pour UIKit — mettez à jour l'interface uniquement via DispatchQueue.main

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi