Come funzionano i meccanismi async e await sotto il cofano?
sobes.tech AI
Risposta dell'AI
Async/await in Swift si basa sulla concorrenza strutturata e utilizza Dispatch/Global Actors. I meccanismi sottostanti sono:
-
Stile di Continuation: Le funzioni asincrone vengono compilate in stile di continuazione. Invece di restituire immediatamente un valore, il controllo viene trasferito al runtime Swift, che salva lo stato corrente della funzione (variabili locali, puntatore di esecuzione). Quando l'operazione asincrona termina, il runtime riprende l'esecuzione della funzione dallo stato salvato.
-
Task: Ogni chiamata a una funzione
asynccrea o si unisce a unaTaskstrutturata. LaTaskrappresenta un'unità di lavoro e forma una gerarchia. LaTaskgenitore aspetta che leTaskfiglie terminino. -
Job: La
Taskviene suddivisa in unità di lavoro più piccole chiamateJob. UnJobrappresenta un frammento di codice che può essere eseguito su un esecutore. -
Esecutore: L'esecutore è responsabile di avviare il
Job. Nella libreria standard, si usanoDispatchQueueglobali come esecutori per la maggior parte delle attività asincrone. I contesti specifici (ad esempio,MainActor) hanno i propri esecutori specializzati. -
Punti di sospensione:
awaitè un punto di sospensione. Quando viene raggiunto, la funzione si sospende, il controllo viene trasferito al codice o esecutore chiamante, e ilJobcorrente termina. Il runtime Swift salva lo stato della funzione. -
Ripresa: Quando l'operazione asincrona attesa con
awaittermina, il runtime Swift crea un nuovoJobper continuare l'esecuzione della funzione sospesa. QuestoJobviene messo in coda sull'esecutore. -
Annullamento: La concorrenza strutturata supporta l'annullamento gerarchico. L'annullamento di un
Taskgenitore annulla automaticamente tutti i suoiTaskfigli. Le operazioni asincrone possono verificare lo stato di annullamento e reagire di conseguenza.
Ecco un esempio semplificato della compilazione di una funzione async:
// Funzione async originale
func fetchData() async -> Data {
// Operazione asincrona
let data = await URLSession.shared.data(from: url).0
return data
}
// Rappresentazione semplificata della compilazione
// Invece di restituire, la funzione accetta una Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
// Codice iniziale della funzione
let url = URL(string: "...")! // Esempio
// Avviare operazione asincrona
URLSession.shared.data(from: url) { data, _, error in
// Questa chiusura viene eseguita dopo il completamento dell'operazione asincrona
if let data = data {
// Passare il risultato alla continuation, riprendendo la funzione
continuation.resume(returning: data)
} else if let error = error {
continuation.resume(throwing: error)
} else {
// Gestione di altri casi
continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
}
}
// La funzione termina qui, aspettando la chiamata a resume della continuation
}
Await è fondamentalmente zucchero sintattico sulla gestione di Continuation e sulla pianificazione di Job sull'esecutore. La sospensione non blocca direttamente il thread, ma consente all'esecutore di eseguire altri Job.