Hogyan működnek az async és await mechanizmusok a háttérben?
sobes.tech MI
Válasz az MI-től
Az Async/await Swiftben a strukturált konkurrencia alapjaira épül, és a Dispatch/Global Actors-t használja. A háttérben működő mechanizmusok a következők:
-
Folytatási stílus: Az aszinkron funkciók folytatási stílusra fordulnak. Ahelyett, hogy azonnal visszaadnák az értéket, az irányítás átkerül a Swift futtatókörnyezetéhez, amely elmenti a függvény aktuális állapotát (helyi változók, végrehajtási mutató). Amikor az aszinkron művelet befejeződik, a futtatókörnyezet folytatja a függvény végrehajtását a mentett állapotból.
-
Task: Minden
asyncfüggvényhívás létrehoz vagy csatlakozik egy strukturáltTask-hoz. ATaskegy munkafolyamatot képvisel, és hierarchiát alkot. A szülőTaskvárja a gyermekTask-ok befejezését. -
Job: A
Taskkisebb munkarészekre, azazJob-okra van bontva. AJobegy kódrészletet képvisel, amely végrehajtható egy végrehajtón (Executor). -
Executor: A végrehajtó felelős a
Jobindításáért. A standard könyvtárban globálisDispatchQueue-kat használnak végrehajtóként a legtöbb aszinkron feladathoz. A speciális kontextusok (pl.MainActor) saját dedikált végrehajtóikkal rendelkeznek. -
Felfüggesztési pontok: Az
awaitegy felfüggesztési pont. Amikor eléri azawait, a függvény szünetel, az irányítás átadódik a hívónak vagy a végrehajtónak, és a jelenlegiJobbefejeződik. A Swift futtatókörnyezet elmenti a függvény állapotát. -
Újraindítás: Amikor az
await-től várt aszinkron művelet befejeződik, a Swift futtatókörnyezet újJob-ot hoz létre a szüneteltetett függvény folytatásához. Ezt aJob-ot sorba állítják a végrehajtóra. -
Megszakítás: A strukturált konkurrencia támogatja a hierarchikus megszakítást. A szülő
Taskmegszakítása automatikusan megszakítja az összes gyermekTask-ját. Az aszinkron műveletek ellenőrizhetik a megszakítási státuszt, és ennek megfelelően reagálhatnak.
Íme egy egyszerűsített példája az async függvény fordításának:
// Kiinduló async függvény
func fetchData() async -> Data {
// Aszinkron művelet
let data = await URLSession.shared.data(from: url).0
return data
}
// Egyszerűsített fordítási ábra
// A visszatérés helyett a függvény a Continuation-t fogadja
func fetchData(_ continuation: Continuation<Data, Error>) {
// A függvény kezdeti kódja
let url = URL(string: "...")! // Példa
// Aszinkron művelet indítása
URLSession.shared.data(from: url) { data, _, error in
// Ez a zárás a művelet befejezése után fut
if let data = data {
// Eredmény átadása a continuation-nek, a függvény újraindítása
continuation.resume(returning: data)
} else if let error = error {
continuation.resume(throwing: error)
} else {
// Egyéb esetek kezelése
continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
}
}
// A függvény itt fejeződik be, várva a resume hívást a continuation-től
}
Az Await lényegében szintaktikus cukor a Continuation kezelése és a Job ütemezése felett a végrehajtón. A szünet nem blokkolja közvetlenül a szálat, hanem lehetővé teszi a végrehajtónak, hogy más Job-okat hajtson végre.