Sobes.tech
Middle+

Ar galima sinchroniškai iškviesti asinchroninį kodą?

sobes.tech AI

Atsakymas iš AI

taip, galima, bet tai gali sukelti problemų, ypač deadlock'us.

Būdai sinchroniškai iškviesti asinchroninį kodą:

  1. Naudojant Result savybę arba Wait() metodą Task objekte:

    // Sinchroninis asinchroninio metodo iškvietimas
    Task.Run(async () => await SomeAsyncTask()).Wait();
    
    // Gauti asinchroninio metodo rezultatą sinchroniškai
    var result = SomeAsyncTaskWithResult().Result;
    
    async Task SomeAsyncTask()
    {
        await Task.Delay(100);
    }
    
    async Task<int> SomeAsyncTaskWithResult()
    {
        await Task.Delay(100);
        return 42;
    }
    
  2. Naudojant GetAwaiter().GetResult():

    // Sinchroninis asinchroninio metodo iškvietimas su rezultato gavimu
    var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
    

Šio metodo trūkumai:

  • Deadlock'ai: Dažniausia problema, ypač UI gijų arba ASP.NET kontekstuose, kur Wait() ir Result blokuoja esamą giją, laukdami užduoties pabaigos. Jei asinchroninė funkcija bando pagauti užblokuotą sinchronizacijos kontekstą tęsti po await, įvyksta deadlock'as.
  • Našumo ir mastelio mažėjimas: Gijų blokavimas vietoje asinchroninių operacijų naudojimo naudoja daugiau išteklių ir sumažina galimybę apdoroti daug vienu metu užklausų (pvz., internetinėse programose).
  • Neaiškus elgesys: Asinchroninio ir sinchroninio kodo maišymas gali padaryti programos vykdymo srautą sudėtingą suprasti ir derinti.

Dažniausiai teisingas būdas yra naudoti await asinchroniniam vykdymui tęsti arba, jei reikia vykdyti asinchroninį kodą programos įėjimo taške (pvz., Main), naudoti Task.Run() kartu su Wait() arba padaryti Main asinchroniniu, jei C# versija tai palaiko (async Task Main).

Saugus pavyzdys:

// Saugus asinchroninio metodo iškvietimas iš sinchroninio konteksto
Task.Run(async () =>
{
    await SomeAsyncTask();
}).Wait();

// Saugus asinchroninio metodo iškvietimas su rezultatu
var result = Task.Run(async () =>
{
    return await SomeAsyncTaskWithResult();
}).Result;