Async y Await en C#: salvando la aplicación de los «congelamientos»
\n\n¿Alguna vez ha ejecutado un programa en C#, presionado un botón y la interfaz se «congeló» durante varios segundos? ¿O tal vez su servidor dejó de responder a nuevas solicitudes mientras procesaba una solicitud «pesada»? ¿Le suena familiar? Este es el problema clásico del código síncrono, donde el hilo de ejecución se bloquea esperando que se complete una operación (lectura de un archivo, consulta a una base de datos, llamada HTTP).
\n\nLa solución a este problema es la programación asíncrona. Y en C#, las herramientas principales para esto son las palabras clave async y await. Si alguna vez se ha preguntado: «¿Cómo y cuándo usar async y await?», ha llegado al lugar correcto. En este tutorial, analizaremos todo, desde lo básico hasta las mejores prácticas, para que escriba código rápido, receptivo y escalable.
Este material se basa en una pregunta popular real de Stack Overflow, que ha acumulado miles de visitas. Lo hemos adaptado para contenido educativo, añadiendo ejemplos de código y explicaciones claras.
\n\n¿Qué son async y await? En palabras sencillas
\n\nImagínese que es un chef (su programa). Necesita preparar la cena. Uno de los platos es una sopa que debe hervir durante 30 minutos. En el mundo síncrono, se quedaría junto a la estufa esperando a que la sopa se cocine, sin hacer nada. Absurdo, ¿verdad?
\n\nLa asincronía es cuando pone la sopa a hervir (async) y, sin esperar, comienza a cortar la ensalada, poner la mesa y hacer otras cosas. Cuando la sopa esté lista, vuelve a ella (await). No pierde tiempo: es eficiente.
- \n
async— un modificador de método que le dice al compilador: «Este método contiene operaciones asíncronas. No bloquees el hilo cuando encuentreawait». \n await— un operador que se aplica a una tarea (Task). Dice: «Pausa la ejecución de este método hasta que la tarea se complete, pero no bloquees el hilo. Tan pronto como la tarea se complete, continúa la ejecución desde este punto». \n
Importante: await no bloquea el hilo. Devuelve el control al código que llama, y el hilo continúa realizando otro trabajo.
¿Cuándo usar async y await?
\n\nEsta es la pregunta más frecuente. La respuesta es simple: siempre que realice una operación que pueda llevar mucho tiempo (operaciones vinculadas a E/S) y no quiera bloquear el hilo.
\n\nEstos son los escenarios típicos:
\n- \n
- Solicitudes de red: Llamadas HTTP (HttpClient), trabajo con WebSocket. \n
- Trabajo con archivos: Lectura/escritura de archivos grandes, trabajo con flujos. \n
- Consultas a bases de datos: Entity Framework, ADO.NET, Dapper. \n
- Trabajo con servicios web: WCF, API REST. \n
- Cualquier operación de entrada/salida (E/S): Acceso a disco, red, impresora. \n
¿Cuándo NO se deben usar async y await?
\n- \n
- Operaciones vinculadas a CPU: Si su tarea requiere cálculos intensivos (renderizado 3D, procesamiento de video, cálculos matemáticos complejos),
async/awaitno ayudará. Aquí debe usarTask.RunoParallelpara paralelizar en varios núcleos de la CPU. \n - En constructores de clases: Los constructores no pueden ser async. Use métodos de fábrica (
public static async Task<MyClass> CreateAsync()). \n - En getters/setters de propiedades: Tampoco pueden ser async. Use métodos. \n
¿Cómo funciona? Análisis con ejemplo de código
\n\nVeamos un código real. Imagine que estamos descargando datos de un servidor remoto.
\n\nEjemplo malo (síncrono)
\npublic string GetDataFromWeb()\n{\n usi