Comment fonctionnent les mécanismes async et await en coulisses?
sobes.tech IA
Réponse de l'IA
Async/await en Swift est basé sur la concurrence structurée et utilise Dispatch/Global Actors. Les mécanismes sous-jacents sont :
-
Style de continuation : Les fonctions asynchrones sont compilées en style de continuations. Au lieu de retourner immédiatement une valeur, le contrôle est transféré au runtime Swift, qui sauvegarde l'état actuel de la fonction (variables locales, pointeur d'exécution). Lorsque l'opération asynchrone se termine, le runtime reprend l'exécution de la fonction depuis l'état sauvegardé.
-
Tâche : Chaque appel à une fonction
asynccrée ou rejoint uneTaskstructurée. LaTaskreprésente une unité de travail et forme une hiérarchie. LaTaskparent attend la fin desTaskenfants. -
Job : La
Taskest divisée en unités de travail plus petites appeléesJob. UnJobreprésente un fragment de code pouvant être exécuté sur un exécuteur. -
Exécuteur : L'exécuteur est responsable du lancement du
Job. La bibliothèque standard utilise desDispatchQueueglobales comme exécuteurs pour la plupart des tâches asynchrones. Les contextes spécifiques (par exemple,MainActor) ont leurs propres exécuteurs spécialisés. -
Points de suspension :
awaitest un point de suspension. Lorsqu'il est atteint, la fonction est suspendue, le contrôle est transféré au code ou à l'exécuteur appelant, et leJobactuel se termine. Le runtime Swift sauvegarde l'état de la fonction. -
Reprise : Lorsque l'opération asynchrone attendue avec
awaitse termine, le runtime Swift crée un nouveauJobpour continuer l'exécution de la fonction suspendue. CeJobest mis en file d'attente sur l'exécuteur. -
Annulation : La concurrence structurée supporte l'annulation hiérarchique. L'annulation d'une
Taskparent annule automatiquement toutes sesTaskenfants. Les opérations asynchrones peuvent vérifier l'état d'annulation et réagir en conséquence.
Voici un exemple simplifié de la compilation d'une fonction async :
// Fonction async d'origine
func fetchData() async -> Data {
// Opération asynchrone
let data = await URLSession.shared.data(from: url).0
return data
}
// Représentation simplifiée de la compilation
// Au lieu de retourner, la fonction accepte une Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
// Code initial de la fonction
let url = URL(string: "...")! // Exemple
// Démarrer l'opération asynchrone
URLSession.shared.data(from: url) { data, _, error in
// Cette clôture s'exécute après la fin de l'opération asynchrone
if let data = data {
// Passer le résultat à la continuation, en reprenant la fonction
continuation.resume(returning: data)
} else if let error = error {
continuation.resume(throwing: error)
} else {
// Gestion d'autres cas
continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
}
}
// La fonction se termine ici, en attendant l'appel à resume de la continuation
}
Await est essentiellement un sucre syntaxique sur la gestion de Continuation et la planification de Job sur l'exécuteur. La suspension ne bloque pas directement le fil, mais permet à l'exécuteur d'exécuter d'autres Job.