Programación asíncrona en C#: guía completa para principiantes
\n\nLa programación asíncrona es uno de los conceptos clave del desarrollo moderno en C#. Permite que tus aplicaciones sigan siendo receptivas sin bloquear el hilo de ejecución durante operaciones largas: lectura de archivos, consultas a bases de datos o llamadas HTTP. En esta guía, analizaremos los fundamentos de la asincronía en C# con ejemplos prácticos.
\n\n¿Qué es la programación asíncrona y por qué es necesaria?
\n\nEn la programación síncrona, el código se ejecuta secuencialmente. Si llamas a un método que espera una respuesta del servidor durante 5 segundos, todo el hilo (UI o de trabajo) se congela. La aplicación "se cuelga". La programación asíncrona resuelve este problema: en lugar de bloquear el hilo, el método devuelve el control al código que lo llamó y, cuando el resultado está listo, lo notifica.
\n\nPrincipales ventajas de la asincronía:
\n- \n
- Capacidad de respuesta de la UI — la interfaz no se congela durante operaciones largas. \n
- Escalabilidad — las aplicaciones de servidor pueden procesar más solicitudes sin crear nuevos hilos. \n
- Eficiencia — los hilos liberados se utilizan para otras tareas. \n
Fundamentos de async/await en C#
\n\nLas palabras clave async y await son la base de la programación asíncrona en C#. Aparecieron en C# 5.0 e hicieron que el código asíncrono fuera casi tan simple como el síncrono.
Reglas de uso:
\n- \n
- El método se marca con la palabra clave
async. \n - El tipo de retorno debe ser
Task,Task<T>ovoid(solo para controladores de eventos). \n - Dentro del método, llama a otros métodos asíncronos con la palabra clave
await. \n
Ejemplo sencillo:
\nusing System;\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main(string[] args)\n {\n Console.WriteLine("Comenzando la descarga...");\n string content = await DownloadWebPageAsync("https://example.com");\n Console.WriteLine($"Caracteres descargados: {content.Length}");\n }\n\n static async Task<string> DownloadWebPageAsync(string url)\n {\n using HttpClient client = new HttpClient();\n string result = await client.GetStringAsync(url);\n return result;\n }\n}\n\nObserva: el método Main también está marcado como async Task — esto es válido a partir de C# 7.1.
Tipos Task, Task<T> y ValueTask
\n\nEn la programación asíncrona de C# se utilizan tres tipos principales de valores de retorno:
\n\n- \n
Task— para métodos que no devuelven un valor (análogo a void). \n Task<T>— para métodos que devuelven un valor de tipo T. \n ValueTask<T>— versión optimizada para escenarios donde el resultado suele estar disponible de forma síncrona (por ejemplo, desde la caché). \n
Ejemplo con Task<T>:
\nstatic async Task<int> CalculateSumAsync(int a, int b)\n{\n await Task.Delay(1000); // Simulación de trabajo largo\n return a + b;\n}\n\n// Llamada:\nint result = await CalculateSumAsync(5, 3);\nConsole.WriteLine(result); // 8\n\nManejo de errores en métodos asíncronos
\n\nLas excepciones en métodos asíncronos se manejan con el bloque estándar try-catch. Sin embargo, hay un matiz importante: la excepción se guarda en el objeto Task y se "relanza" al usar await.
static async Task<string> ReadFileAsync(string path)\n{\n try\n {\n string content = await File.ReadAllTextAsync(path);\n return content;\n }\n catch (FileNotFoundException ex)\n {\n Console.WriteLine($"Archivo no encontrado: {ex.Message