Sobes.tech
Middle+

¿Se puede llamar a código asíncrono de forma sincrónica?

sobes.tech AI

Respuesta de la IA

Sí, es posible, pero puede causar problemas, en particular, bloqueos.

Formas de llamar de manera síncrona a código asíncrono:

  1. Uso de la propiedad Result o del método Wait() en un objeto Task.

    // Llamada síncrona a un método asíncrono
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Obtener el resultado de un método asíncrono de forma síncrona
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Uso de GetAwaiter().GetResult():

    // Llamada síncrona a un método asíncrono con obtención del resultado
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Desventajas de este enfoque:

  • Bloqueos: El problema más común, especialmente en hilos de interfaz de usuario o contextos ASP.NET con sincronización de contexto. Wait() y Result bloquean el hilo actual esperando que la tarea termine. Si el método asíncrono intenta capturar el contexto de sincronización bloqueado para continuar después de await, se produce un bloqueo.
  • Reducción del rendimiento y escalabilidad: Bloquear hilos en lugar de usar operaciones asíncronas consume más recursos y reduce la capacidad de la aplicación para manejar múltiples solicitudes simultáneas (por ejemplo, en aplicaciones web).
  • Comportamiento no evidente: Mezclar código asíncrono y síncrono puede hacer que el flujo de ejecución sea difícil de entender y depurar.

En la mayoría de los casos, la mejor práctica es usar await para continuar la ejecución asíncrona o, si es necesario ejecutar código asíncrono en el punto de entrada de la aplicación (por ejemplo, Main), usar Task.Run() junto con Wait() o hacer que Main sea asíncrono, si la versión de C# lo soporta (async Task Main).

Ejemplo de llamada segura a código asíncrono desde un método síncrono, usando Task.Run para mover la ejecución al pool de hilos:

// Llamada segura a un método asíncrono desde un contexto síncrono
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Llamada segura a un método asíncrono con resultado
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;