Wie funktionieren die Mechanismen async und await im Hintergrund?
sobes.tech KI
Antwort von AI
Async/await in Swift basiert auf strukturierter Nebenläufigkeit und verwendet Dispatch/Global Actors. Die zugrunde liegenden Mechanismen sind:
-
Fortsetzungsstil: Asynchrone Funktionen werden in einem Fortsetzungsstil kompiliert. Anstatt sofort einen Wert zurückzugeben, wird die Kontrolle an die Swift-Laufzeit übergeben, die den aktuellen Zustand der Funktion (lokale Variablen, Ausführungspointer) speichert. Wenn die asynchrone Operation abgeschlossen ist, setzt die Laufzeit die Ausführung der Funktion aus dem gespeicherten Zustand fort.
-
Aufgabe: Jeder Aufruf einer
async-Funktion erstellt oder verbindet sich mit einer strukturiertenTask. DieTaskrepräsentiert eine Arbeitseinheit und bildet eine Hierarchie. Die Eltern-Taskwartet auf das Ende der Kind-Task. -
Job: Die
Taskwird in kleinere Arbeitseinheiten namensJobunterteilt. EinJobstellt ein Codefragment dar, das auf einem Executor ausgeführt werden kann. -
Executor: Der Executor ist verantwortlich für das Starten eines
Job. In der Standardbibliothek werden globaleDispatchQueueals Executor für die meisten asynchronen Aufgaben verwendet. Spezifische Kontexte (z.B.MainActor) haben ihre eigenen spezialisierten Executor. -
Suspensionspunkte:
awaitist ein Suspensionspunkt. Beim Erreichen wird die Funktion ausgesetzt, die Kontrolle an den aufrufenden Code oder Executor übertragen und der aktuelleJobbeendet. Die Swift-Laufzeit speichert den Zustand der Funktion. -
Wiederaufnahme: Wenn die asynchrone Operation, auf die
awaitwartet, beendet ist, erstellt die Swift-Laufzeit einen neuenJob, um die Ausführung der angehaltenen Funktion fortzusetzen. DieserJobwird in die Warteschlange des Executors gestellt. -
Abbruch: Die strukturierte Nebenläufigkeit unterstützt hierarchisches Abbrechen. Das Abbrechen eines Eltern-
Taskbeendet automatisch alle ihre Kind-Task. Asynchrone Operationen können den Abbruchstatus prüfen und entsprechend reagieren.
Hier ein vereinfachtes Beispiel für die Kompilierung einer async-Funktion:
// Ursprüngliche async-Funktion
func fetchData() async -> Data {
// Asynchrone Operation
let data = await URLSession.shared.data(from: url).0
return data
}
// Vereinfachte Darstellung der Kompilierung
// Anstelle der Rückgabe akzeptiert die Funktion eine Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
// Anfangscode der Funktion
let url = URL(string: "...")! // Beispiel
// Starten der asynchronen Operation
URLSession.shared.data(from: url) { data, _, error in
// Dieser Abschluss wird nach Abschluss der asynchronen Operation ausgeführt
if let data = data {
// Ergebnis an die Continuation übergeben, Funktion wieder aufnehmen
continuation.resume(returning: data)
} else if let error = error {
continuation.resume(throwing: error)
} else {
// Behandlung anderer Fälle
continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
}
}
// Funktion endet hier, wartet auf den Aufruf von resume der Continuation
}
Await ist im Wesentlichen syntaktischer Zucker für die Verwaltung von Continuation und die Planung von Job auf dem Executor. Das Aussetzen blockiert den Thread nicht direkt, sondern ermöglicht es dem Executor, andere Jobs auszuführen.