¿Cómo funcionan los mecanismos async y await por debajo del capó?
sobes.tech AI
Respuesta de la IA
Async/await en Swift se basa en la concurrencia estructurada y utiliza Dispatch/Global Actors. Los mecanismos que trabajan detrás de escena son:
-
Estilo de Continuación: Las funciones asíncronas se compilan en un estilo de continuaciones. En lugar de devolver inmediatamente un valor, el control se transfiere al runtime de Swift, que guarda el estado actual de la función (variables locales, puntero de ejecución). Cuando la operación asíncrona termina, el runtime reanuda la ejecución de la función desde el estado guardado.
-
Tarea: Cada llamada a una función
asynccrea o se une a unaTaskestructurada. LaTaskrepresenta una unidad de trabajo y forma una jerarquía. LaTaskpadre espera a que las tareas hijas terminen. -
Trabajo: La
Taskse divide en unidades de trabajo más pequeñas llamadasJob. UnJobrepresenta un fragmento de código que puede ser ejecutado en un ejecutor. -
Ejecutor: El ejecutor es responsable de lanzar el
Job. En la biblioteca estándar, se usanDispatchQueueglobales como ejecutores para la mayoría de las tareas asíncronas. Los contextos específicos (por ejemplo,MainActor) tienen sus propios ejecutores especializados. -
Puntos de suspensión:
awaites un punto de suspensión. Cuando se alcanza unawait, la función se suspende, el control se transfiere al código o ejecutor que llamó, y elJobactual termina. El runtime de Swift guarda el estado de la función. -
Reanudación: Cuando la operación asíncrona en la que se esperaba con
awaittermina, el runtime de Swift crea un nuevoJobpara continuar la ejecución de la función suspendida. EsteJobse pone en la cola del ejecutor. -
Cancelación: La concurrencia estructurada soporta cancelación jerárquica. La cancelación de una
Taskpadre cancela automáticamente todas susTaskhijas. Las operaciones asíncronas pueden verificar el estado de cancelación y reaccionar en consecuencia.
Aquí un ejemplo simplificado de la compilación de una función async:
// Función async original
func fetchData() async -> Data {
// Operación asíncrona
let data = await URLSession.shared.data(from: url).0
return data
}
// Representación simplificada de la compilación
// En lugar de devolver, la función recibe una Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
// Código inicial de la función
let url = URL(string: "...")! // Ejemplo
// Iniciar operación asíncrona
URLSession.shared.data(from: url) { data, _, error in
// Este cierre se ejecuta después de que la operación asíncrona termina
if let data = data {
// Pasar el resultado a la continuation, reanudando la función
continuation.resume(returning: data)
} else if let error = error {
continuation.resume(throwing: error)
} else {
// Manejo de otros casos
continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
}
}
// La función termina aquí, esperando que la llamada a resume de la continuation
}
Await es básicamente azúcar sintáctico sobre la gestión de Continuation y la planificación de Job en el ejecutor. La suspensión no bloquea directamente el hilo, sino que permite que el ejecutor ejecute otros Job.