web-dev-qa-db-fra.com

wait vs Task.Wait - Impasse?

Je ne comprends pas très bien la différence entre Task.Wait et await.

J'ai quelque chose de similaire aux fonctions suivantes dans un service ASP.NET WebAPI:

public class TestController : ApiController
{
    public static async Task<string> Foo()
    {
        await Task.Delay(1).ConfigureAwait(false);
        return "";
    }

    public async static Task<string> Bar()
    {
        return await Foo();
    }

    public async static Task<string> Ros()
    {
        return await Bar();
    }

    // GET api/test
    public IEnumerable<string> Get()
    {
        Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());

        return new string[] { "value1", "value2" }; // This will never execute
    }
}

Get sera dans l'impasse.

Qu'est-ce qui pourrait causer ça? Pourquoi cela ne pose-t-il pas un problème lorsque j'utilise une attente de blocage plutôt que await Task.Delay?

135
ronag

Wait et await - bien que conceptuellement similaires - sont en réalité complètement différents.

Wait bloquera de manière synchrone jusqu'à la fin de la tâche. Le thread actuel est donc littéralement bloqué dans l'attente de la fin de la tâche. En règle générale, vous devez utiliser "async tout en bas"; en d'autres termes, ne bloquez pas le code async. Sur mon blog, je vais dans les détails de comment le blocage en code asynchrone provoque un blocage .

await attendra de manière asynchrone la fin de la tâche. Cela signifie que la méthode actuelle est "suspendue" (son état est capturé) et que la méthode renvoie une tâche incomplète à son appelant. Plus tard, lorsque l'expression await est terminée, le reste de la méthode est planifié en tant que suite.

Vous avez également mentionné un "bloc coopératif", par lequel je suppose que vous entendez une tâche sur laquelle vous êtes Waiting peut être exécutée sur le thread en attente. Cela peut arriver dans certaines situations, mais c'est une optimisation. Ne peut pas se produire dans de nombreuses situations, par exemple si la tâche est destinée à un autre planificateur, si elle est déjà lancée ou s'il ne s'agit pas d'une tâche non codée (comme dans votre exemple de code: Wait ne peut pas exécuter la Delay tâche en ligne car il n'y a pas de code pour cela).

Vous pouvez trouver ma async/await intro utile.

200
Stephen Cleary

D'après ce que j'ai lu de différentes sources:

Une expression wait ne bloque pas le thread sur lequel elle s'exécute. Au lieu de cela, le compilateur inscrit le reste de la méthode asynchrone en tant que continuation de la tâche attendue. Le contrôle retourne ensuite à l'appelant de la méthode async. Lorsque la tâche est terminée, elle appelle sa continuation et l'exécution de la méthode asynchrone reprend là où elle s'était arrêtée.

Pour attendre la fin de la tâche task , vous pouvez appeler sa méthode Task.Wait. Un appel à la méthode Wait bloque le thread appelant jusqu'à l'exécution complète de l'instance de classe unique. La méthode Wait () sans paramètre est utilisée pour attendre inconditionnellement jusqu'à la fin d'une tâche. La tâche simule le travail en appelant la méthode Thread.Sleep pour la mettre en veille pendant deux secondes.

Cet article est également une bonne lecture.

0
Ayushmati