Sobes.tech
Senior

Kako funkcionišu mehanizmi async i await ispod haube?

sobes.tech АИ

Одговор од АИ

Async/await u Swiftu zasnovan je na strukturiranoj konkurenciji i koristi Dispatch/Global Actors. Mehanizmi koji rade ispod haube su:

  1. Stil nastavka: Asinhrone funkcije se kompajliraju u stil nastavka. Umesto da odmah vrate vrednost, kontrola se prenosi na Swift runtime, koji čuva trenutno stanje funkcije (lokalne promenljive, pokazivač izvršenja). Kada asinhrona operacija završi, runtime nastavlja izvršenje funkcije od sačuvanog stanja.

  2. Task: Svaki poziv async funkcije kreira ili se pridružuje strukturiranoj Task. Task predstavlja jedinicu rada i formira hijerarhiju. Roditeljski Task čeka završetak podređenih Task.

  3. Job: Task se razbija na manje jedinice rada, nazvane Job. Job predstavlja fragment koda koji može biti izvršen na izvršiocu (Executor).

  4. Executor: Izvršilac je odgovoran za pokretanje Job. U standardnoj biblioteci se koriste globalni DispatchQueue kao izvršioci za većinu asinhronih zadataka. Specijalizovani konteksti (npr., MainActor) imaju svoje specijalizovane izvršioca.

  5. Tačke suspendovanja: await je tačka suspendovanja (suspension point). Kada dosegne await, funkcija se zaustavlja, kontrola se prenosi na pozivajući kod ili izvršioca, a trenutni Job se završava. Swift runtime čuva stanje funkcije.

  6. Resumption: Kada asinhrona operacija na koju je čekao await završi, Swift runtime kreira novi Job za nastavak izvršavanja suspendovane funkcije. Ovaj Job se stavlja u red na izvršiocu.

  7. Otkazivanje: Strukturirana konkurencija podržava hijerarhijsko otkazivanje. Otkazivanje roditeljskog Task automatski otkazuje sve njegove podređene Task. Asinhrone operacije mogu proveravati status otkazivanja i reagovati u skladu s tim.

Evo pojednostavljenog primera kompilacije async funkcije:

// Početna async funkcija
func fetchData() async -> Data {
    // Asinhrona operacija
    let data = await URLSession.shared.data(from: url).0
    return data
}

// Pojednostavljeni prikaz kompilacije
// Umesto povratka, funkcija prihvata Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
    // Početni kod funkcije
    let url = URL(string: "...")! // Primer
    
    // Pokretanje asinhrone operacije
    URLSession.shared.data(from: url) { data, _, error in
        // Ovaj blok se izvršava nakon završetka asinhrone operacije
        if let data = data {
            // Prenos rezultata u continuation, nastavak funkcije
            continuation.resume(returning: data)
        } else if let error = error {
            continuation.resume(throwing: error)
        } else {
            // Obrada drugih slučajeva
            continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
        }
    }
    // Funkcija se završava ovde, čekajući poziv resume od continuation
}

Await je u suštini sintaktički šećer nad upravljanjem Continuation i planiranjem Job na izvršiocu. Zaustavljanje ne blokira direktno nit, već omogućava izvršiocu da izvršava druge Job-ove.