C# Language Le blocage sur du code asynchrone peut provoquer des blocages


Exemple

Il est déconseillé de bloquer les appels asynchrones car cela peut provoquer des blocages dans des environnements dotés d'un contexte de synchronisation. La meilleure pratique consiste à utiliser Async / Wait "tout en bas". Par exemple, le code Windows Forms suivant provoque un blocage:

private async Task<bool> TryThis()
{
    Trace.TraceInformation("Starting TryThis");
    await Task.Run(() =>
    {
        Trace.TraceInformation("In TryThis task");
        for (int i = 0; i < 100; i++)
        {
            // This runs successfully - the loop runs to completion
            Trace.TraceInformation("For loop " + i);
            System.Threading.Thread.Sleep(10);
        }
    });

    // This never happens due to the deadlock
    Trace.TraceInformation("About to return");
    return true;
}

// Button click event handler
private void button1_Click(object sender, EventArgs e)
{
    // .Result causes this to block on the asynchronous call
    bool result = TryThis().Result;
    // Never actually gets here
    Trace.TraceInformation("Done with result");
}

Essentiellement, une fois l'appel asynchrone terminé, il attend que le contexte de synchronisation devienne disponible. Cependant, le gestionnaire d'événement "conserve" le contexte de synchronisation pendant qu'il attend que la méthode TryThis() se termine, provoquant ainsi une attente circulaire.

Pour corriger cela, le code doit être modifié pour

private async void button1_Click(object sender, EventArgs e)
{
  bool result = await TryThis();
  Trace.TraceInformation("Done with result");
}

Remarque: les gestionnaires d'événements sont le seul endroit où async void doit être utilisé (car vous ne pouvez pas attendre une méthode async void ).