Sobes.tech
Middle+

É possível chamar código assíncrono de forma síncrona?

sobes.tech IA

Resposta da IA

Sim, é possível, mas isso pode causar problemas, especialmente deadlocks.

Formas de chamar código assíncrono de forma síncrona:

  1. Uso da propriedade Result ou do método Wait() em um objeto Task.

    // Chamada síncrona de um método assíncrono
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Obter o resultado de um método assí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():

    // Chamada síncrona de um método assíncrono com obtenção do resultado
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Desvantagens dessa abordagem:

  • Deadlocks: O problema mais comum, especialmente em threads de interface gráfica ou contextos ASP.NET com sincronização de contexto. Wait() e Result bloqueiam a thread atual esperando a conclusão da tarefa. Se o método assíncrono tentar capturar o contexto de sincronização bloqueado para continuar após await, ocorre um deadlock.
  • Redução de desempenho e escalabilidade: Bloquear threads ao invés de usar operações assíncronas consome mais recursos e reduz a capacidade do aplicativo de lidar com múltiplas requisições simultâneas (por exemplo, em aplicações web).
  • Comportamento não intuitivo: Misturar código assíncrono e síncrono pode tornar o fluxo de execução difícil de entender e depurar.

Na maioria dos casos, a abordagem correta é usar await para continuar a execução assíncrona ou, se necessário executar código assíncrono na entrada do aplicativo (por exemplo, Main), usar Task.Run() junto com Wait() ou tornar Main assíncrono, se a versão do C# suportar (async Task Main).

Exemplo de chamada segura de código assíncrono de um método síncrono, usando Task.Run para mover a execução para o pool de threads:

// Chamada segura de método assíncrono de um contexto síncrono
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Chamada segura de método assíncrono com resultado
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;