Sobes.tech
Senior

Kaip veikia async ir await mechanizmai po gaubtu?

sobes.tech AI

Atsakymas iš AI

Swift-те Async/await struktūruota konkurencija yra pagrįsta ir naudoja Dispatch/Global Actors. Mechanizmai, kurie veikia užkulisiuose, yra:

  1. Tęsinio stilius: Asinchroninės funkcijos kompiliuojamos į tęsinio stilių. Vietoj tiesioginio grąžinimo reikšmės, valdymas perduodamas Swift runtime, kuris išsaugo funkcijos dabartinę būseną (vietines kintamąsias, vykdymo rodyklę). Kai asinchroninė operacija baigiasi, runtime atnaujina funkcijos vykdymą iš išsaugotos būsenos.

  2. Task: Kiekvienas async funkcijos kvietimas sukuria arba prisijungia prie struktūruoto Task. Task atstovauja darbo vienetą ir sukuria hierarchiją. Tėvinis Task laukia vaikų Task užbaigimo.

  3. Job: Task yra suskaidomas į mažesnius darbo vienetus, vadinamus Job. Job atstovauja kodo fragmentą, kuris gali būti vykdomas vykdytoju (Executor).

  4. Executor: Vykdytojas yra atsakingas už Job paleidimą. Standartinėje bibliotekoje naudojami globalūs DispatchQueue kaip vykdytojai daugumai asinchroninių užduočių. Specializuoti kontekstai (pvz., MainActor) turi savo specializuotus vykdytojus.

  5. Sustabdymo taškai: await yra sustabdymo taškas. Pasiekus await, funkcija sustoja, valdymas perduodamas kviečiančiam kodui arba vykdytojui, o dabartinis Job užbaigiasi. Swift runtime išsaugo funkcijos būseną.

  6. Atnaujinimas: Kai asinchroninė operacija, kurios laukė await, baigiasi, Swift runtime sukuria naują Job tęsti sustabdytos funkcijos vykdymą. Šis Job įtraukiamas į vykdytojo eilę.

  7. Atšaukimas: Struktūruota konkurencija palaiko hierarchinį atšaukimą. Tėvinis Task atšaukimas automatiškai atšaukia visus jo vaiko Task. Asinchroninės operacijos gali tikrinti atšaukimo būseną ir atitinkamai reaguoti.

Štai supaprastintas async funkcijos kompiliacijos pavyzdys:

// Pradinė async funkcija
func fetchData() async -> Data {
    // Asinchroninė operacija
    let data = await URLSession.shared.data(from: url).0
    return data
}

// Supaprastintas kompiliacijos vaizdas
// Vietoj grąžinimo, funkcija priima Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
    // Funkcijos pradinis kodas
    let url = URL(string: "...")! // Pavyzdys
    
    // Asinchroninės operacijos paleidimas
    URLSession.shared.data(from: url) { data, _, error in
        // Šis blokas vykdomas po asinchroninės operacijos pabaigos
        if let data = data {
            // Rezultato perdavimas į continuation, funkcijos atnaujinimas
            continuation.resume(returning: data)
        } else if let error = error {
            continuation.resume(throwing: error)
        } else {
            // Kitų atvejų apdorojimas
            continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
        }
    }
    // Funkcija baigiasi čia, laukia resume iškvietimo iš continuation
}

Await iš esmės yra sintaksinis cukrus, kuris yra virš Continuation valdymo ir Job planavimo vykdytojui. Sustojimas tiesiogiai neužblokuoja srauto, bet leidžia vykdytojui vykdyti kitus Job-us.