Hoe werken de mechanismen async en await onder de motorkap?
sobes.tech AI
Antwoord van AI
Async/await in Swift is gebaseerd op gestructureerde gelijktijdigheid en gebruikt Dispatch/Global Actors. De onderliggende mechanismen zijn:
-
Continuatiestijl: Asynchrone functies worden gecompileerd in een continuatiestijl. In plaats van direct een waarde terug te geven, wordt de controle overgedragen aan de Swift-runtime, die de huidige staat van de functie (lokale variabelen, uitvoeringspointer) opslaat. Wanneer de asynchrone operatie voltooid is, hervat de runtime de uitvoering van de functie vanaf de opgeslagen staat.
-
Taak: Elke aanroep van een
asyncfunctie creëert of sluit zich aan bij een gestructureerdeTask. DeTaskvertegenwoordigt een eenheid van werk en vormt een hiërarchie. De ouder-Taskwacht op de voltooiing van de kind-Tasks. -
Job: De
Taskwordt opgedeeld in kleinere eenheden van werk, genaamdJob. EenJobvertegenwoordigt een stuk code dat op een executor kan worden uitgevoerd. -
Executor: De executor is verantwoordelijk voor het starten van een
Job. In de standaardbibliotheek worden globaleDispatchQueues gebruikt als executors voor de meeste asynchrone taken. Specifieke contexten (bijvoorbeeldMainActor) hebben hun eigen gespecialiseerde executors. -
Suspension points:
awaitis een suspension point. Bij het bereiken wordt de functie gepauzeerd, wordt de controle overgedragen aan de aanroepende code of executor, en wordt de huidigeJobbeëindigd. De Swift-runtime slaat de staat van de functie op. -
Hervatting: Wanneer de asynchrone operatie waarop werd gewacht met
awaitvoltooid is, creëert de Swift-runtime een nieuweJobom de uitvoering van de gepauzeerde functie voort te zetten. DezeJobwordt in de wachtrij van de executor geplaatst. -
Annulering: Gestructureerde gelijktijdigheid ondersteunt hiërarchische annulering. Het annuleren van een ouder-
Taskannuleert automatisch al zijn kind-Tasks. Asynchrone operaties kunnen de annuleringstatus controleren en hierop reageren.
Hier is een vereenvoudigd voorbeeld van de compilatie van een async functie:
// Oorspronkelijke async functie
func fetchData() async -> Data {
// Asynchrone operatie
let data = await URLSession.shared.data(from: url).0
return data
}
// Vereenvoudigde representatie van de compilatie
// In plaats van te retourneren, accepteert de functie een Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
// Initiële code van de functie
let url = URL(string: "...")! // Voorbeeld
// Start de asynchrone operatie
URLSession.shared.data(from: url) { data, _, error in
// Deze afsluiting wordt uitgevoerd na voltooiing van de asynchrone operatie
if let data = data {
// Geef het resultaat door aan de continuation, hervat de functie
continuation.resume(returning: data)
} else if let error = error {
continuation.resume(throwing: error)
} else {
// Afhandeling van andere gevallen
continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
}
}
// De functie eindigt hier, wachtend op de call van resume van de continuation
}
Await is in wezen suiker voor het beheer van Continuation en het plannen van Job op de executor. De pauzering blokkeert de thread niet direct, maar stelt de executor in staat om andere Jobs uit te voeren.