Middle+
È possibile chiamare codice asincrono in modo sincrono?
sobes.tech AI
Risposta dell'AI
Sì, è possibile, ma può causare problemi, in particolare deadlock.
Metodi per chiamare codice asincrono in modo sincrono:
-
Uso della proprietà
Resulto del metodoWait()su un oggettoTask.// Chiamata sincrona di un metodo asincrono Task.Run(async () => await SomeAsyncTask()).Wait(); // Ottenere il risultato di un metodo asincrono in modo sincrono var result = SomeAsyncTaskWithResult().Result;async Task SomeAsyncTask() { await Task.Delay(100); } async Task<int> SomeAsyncTaskWithResult() { await Task.Delay(100); return 42; } -
Uso di
GetAwaiter().GetResult():// Chiamata sincrona di un metodo asincrono con ottenimento del risultato var result = SomeAsyncTaskWithResult().GetAwaiter().GetResult();
Svantaggi di questo approccio:
- Deadlock: Il problema più comune, specialmente nei thread UI o nei contesti ASP.NET con sincronizzazione del contesto.
Wait()eResultbloccano il thread corrente in attesa del completamento del task. Se il metodo asincrono tenta di catturare il contesto di sincronizzazione bloccato per continuare dopoawait, si verifica un deadlock. - Riduzione delle prestazioni e scalabilità: Bloccare i thread invece di usare operazioni asincrone consuma più risorse e riduce la capacità dell'applicazione di gestire molte richieste contemporaneamente (ad esempio, nelle applicazioni web).
- Comportamento non intuitivo: Mescolare codice asincrono e sincrono può rendere difficile comprendere e debugare il flusso di esecuzione.
Nella maggior parte dei casi, la pratica corretta è usare await per continuare l'esecuzione asincrona o, se necessario, eseguire codice asincrono nel punto di ingresso dell'applicazione (ad esempio, Main), usando Task.Run() con Wait() o rendendo Main asincrono, se la versione di C# lo supporta (async Task Main).
Esempio di chiamata sicura di codice asincrono da un metodo sincrono, usando Task.Run per spostare l'esecuzione nel pool di thread:
// Chiamata sicura di un metodo asincrono da un contesto sincrono
Task.Run(async () =>
{
await SomeAsyncTask();
}).Wait();
// Chiamata sicura di un metodo asincrono con risultato
var result = Task.Run(async () =>
{
return await SomeAsyncTaskWithResult();
}).Result;