Middle+
Je možné volať asynchrónny kód synchronne?
sobes.tech AI
Odpoveď od AI
Áno, je to možné, ale môže to viesť k problémom, najmä k deadlockom.
Spôsoby synchronného volania asynchrónneho kódu:
-
Použitie vlastnosti
Resultalebo metódyWait()objektuTask.// Synchronné volanie asynchrónnej metódy Task.Run(async () => await SomeAsyncTask()).Wait(); // Získanie výsledku asynchrónnej metódy synchronne var result = SomeAsyncTaskWithResult().Result;async Task SomeAsyncTask() { await Task.Delay(100); } async Task<int> SomeAsyncTaskWithResult() { await Task.Delay(100); return 42; } -
Použitie
GetAwaiter().GetResult():// Synchronné volanie asynchrónnej metódy s získaním výsledku var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
Nevýhody takéhoto prístupu:
- Deadlocky: Najčastejší problém, najmä v UI vláknach alebo ASP.NET kontextoch so synchronization context-om.
Wait()aResultblokujú aktuálne vlákno, čakajúc na dokončenie úlohy. Ak sa asynchrónna metóda pokúša zachytiť zablokovaný kontext synchronizácie na pokračovanie poawait, dochádza k deadlocku. - Zhoršenie výkonu a škálovateľnosti: Blokovanie vlákien namiesto použitia asynchrónnych operácií spotrebúva viac zdrojov a znižuje schopnosť aplikácie spracovať veľké množstvo súčasných požiadaviek (napríklad v webových aplikáciách).
- Nejasné správanie: Miešanie asynchrónneho a synchronného kódu môže spôsobiť, že tok vykonávania programu bude zložitý na pochopenie a ladenie.
Vo väčšine prípadov je správny prístup používať await na pokračovanie asynchrónneho vykonávania alebo, ak je potrebné vykonať asynchrónny kód v vstupe do aplikácie (napríklad Main), použiť Task.Run() v kombinácii s Wait() alebo vytvoriť Main ako asynchrónny, ak to verzia C# podporuje (async Task Main).
Príklad bezpečného volania asynchrónneho kódu zo synchronickej metódy pomocou Task.Run na presun vykonávania do poolu vlákien:
// Bezpečné volanie asynchrónnej metódy zo synchronického kontextu
Task.Run(async () =>
{
await SomeAsyncTask();
}).Wait();
// Bezpečné volanie asynchrónnej metódy s výsledkom
var result = Task.Run(async () =>
{
return await SomeAsyncTaskWithResult();
}).Result;