Sobes.tech
Middle+

Se poate apela codul asincron în mod sincron?

sobes.tech AI

Răspuns de la AI

Da, este posibil, dar poate cauza probleme, în special blocaje.

Moduri de a apela cod asincron în mod sincronic:

  1. Utilizarea proprietății Result sau a metodei Wait() pe un obiect Task.

    // Apel sincronic al unei metode asincrone
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Obținerea rezultatului unei metode asincrone în mod sincronic
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Utilizarea GetAwaiter().GetResult():

    // Apel sincronic al unei metode asincrone cu obținerea rezultatului
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Dezavantaje ale acestei abordări:

  • Blocaje: Problema cea mai frecventă, mai ales în firele UI sau în contexte ASP.NET cu context de sincronizare. Wait() și Result blochează firul curent, așteptând finalizarea sarcinii. Dacă metoda asincronă încearcă să captureze contextul de sincronizare blocat pentru a continua după await, apare un deadlock.
  • Scăderea performanței și scalabilității: Blocarea firelor în loc să se folosească operații asincrone consumă mai multe resurse și reduce capacitatea aplicației de a gestiona multiple solicitări simultane (de exemplu, în aplicațiile web).
  • Comportament neclar: Combinarea codului asincron și sincron poate face fluxul de execuție dificil de înțeles și de depanat.

În cele mai multe cazuri, abordarea corectă este să folosiți await pentru a continua execuția asincronă sau, dacă trebuie să executați cod asincron în punctul de intrare al aplicației (de exemplu, Main), să folosiți Task.Run() împreună cu Wait() sau să faceți Main asincron, dacă versiunea de C# o suportă (async Task Main).

Exemplu de apel sigur al codului asincron dintr-o metodă sincronă, folosind Task.Run pentru mutarea execuției în pool-ul de fire:

// Apel sigur al unei metode asincrone dintr-un context sincron
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Apel sigur al unei metode asincrone cu rezultat
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;