Sobes.tech
Senior

Cum funcționează mecanismele async și await în spate?

sobes.tech AI

Răspuns de la AI

Async/await în Swift se bazează pe concurența structurată și utilizează Dispatch/Global Actors. Mecanismele de bază sunt:

  1. Stil de continuare: Funcțiile asincrone sunt compilate în stil de continuare. În loc să returneze imediat o valoare, controlul este transferat la runtime-ul Swift, care salvează starea curentă a funcției (variabile locale, pointer de execuție). Când operația asincronă se încheie, runtime-ul reia execuția funcției din starea salvată.

  2. Task: Fiecare apel al unei funcții async creează sau se alătură unui Task structurat. Task reprezintă o unitate de muncă și formează o ierarhie. Task părinte așteaptă finalizarea task-urilor copil.

  3. Job: Task este împărțit în unități mai mici de muncă numite Job. Un Job reprezintă un fragment de cod care poate fi executat pe un executor.

  4. Executor: Executorul este responsabil pentru lansarea unui Job. În biblioteca standard, se folosesc DispatchQueue globale ca executori pentru majoritatea sarcinilor asincrone. Contextele specifice (de exemplu, MainActor) au propriile executori specializate.

  5. Puncte de suspendare: await este un punct de suspendare. La atingere, funcția se suspendă, controlul este transferat către codul sau executorul apelant, iar Job-ul curent se încheie. Runtime-ul Swift salvează starea funcției.

  6. Reîncepere: Când operația asincronă așteptată cu await se încheie, runtime-ul Swift creează un nou Job pentru a continua execuția funcției suspendate. Acest Job este plasat în coada executorului.

  7. Anulare: Concurența structurată suportă anularea ierarhică. Anularea unui Task părinte anulează automat toate Task-urile sale copil. Operațiile asincrone pot verifica starea de anulare și pot reacționa corespunzător.

Iată un exemplu simplificat al compilării unei funcții async:

// Funcție async originală
func fetchData() async -> Data {
    // Operație asincronă
    let data = await URLSession.shared.data(from: url).0
    return data
}

// Reprezentare simplificată a compilării
// În loc să returneze, funcția acceptă o Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
    // Codul inițial al funcției
    let url = URL(string: "...")! // Exemplu
    
    // Începerea operației asincrone
    URLSession.shared.data(from: url) { data, _, error in
        // Această închidere se execută după finalizarea operației asincrone
        if let data = data {
            // Transmite rezultatul în continuation, reluând funcția
            continuation.resume(returning: data)
        } else if let error = error {
            continuation.resume(throwing: error)
        } else {
            // Tratarea altor cazuri
            continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
        }
    }
    // Funcția se termină aici, așteptând apelul de resume de la continuation
}

Await este în esență zahăr sintactic peste gestionarea Continuation și planificarea Job pe executor. Suspendarea nu blochează direct firul, ci permite executorului să execute alte Job-uri.