web-dev-qa-db-fra.com

wait Task.Delay () vs. Task.Delay (). Wait ()

En C #, j'ai deux exemples simples suivants:

[Test]
public void TestWait()
{
    var t = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Start");
        Task.Delay(5000).Wait();
        Console.WriteLine("Done");
    });
    t.Wait();
    Console.WriteLine("All done");
}

[Test]
public void TestAwait()
{
    var t = Task.Factory.StartNew(async () =>
    {
        Console.WriteLine("Start");
        await Task.Delay(5000);
        Console.WriteLine("Done");
    });
    t.Wait();
    Console.WriteLine("All done");
}

Le premier exemple crée une tâche qui imprime "Démarrer", attend 5 secondes, affiche "Terminé", puis termine la tâche. J'attends la fin de la tâche puis imprime "Tout est fait". Lorsque je lance le test, il se déroule comme prévu.

Le deuxième test doit avoir le même comportement, sauf que l'attente à l'intérieur de la tâche doit être non bloquante en raison de l'utilisation de l'asynchrone et attendre. Mais ce test n'imprime que "Démarrer" puis immédiatement "Tout est terminé" et "Terminé" n'est jamais imprimé.

Je ne sais pas pourquoi j'ai ce comportement: S Toute aide serait très appréciée :)

45
svenskmand

Le deuxième test comporte deux tâches imbriquées et vous attendez la plus externe. Pour résoudre ce problème, vous devez utiliser t.Result.Wait(). t.Result Obtient la tâche interne.

La seconde méthode est à peu près équivalente à ceci:

public void TestAwait()
{
  var t = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Start");
                return Task.Factory.StartNew(() =>
                {
                    Task.Delay(5000).Wait(); Console.WriteLine("Done");
                });
            });
            t.Wait();
            Console.WriteLine("All done");
}

En appelant t.Wait(), vous attendez la tâche la plus externe qui revient immédiatement.


La meilleure façon de gérer ce scénario consiste à renoncer à utiliser Wait et à simplement utiliser await. Wait peut causer problèmes d'interblocage une fois que vous avez attaché une interface utilisateur à votre code async.

    [Test]
    public async Task TestCorrect() //note the return type of Task. This is required to get the async test 'waitable' by the framework
    {
        await Task.Factory.StartNew(async () =>
        {
            Console.WriteLine("Start");
            await Task.Delay(5000);
            Console.WriteLine("Done");
        }).Unwrap(); //Note the call to Unwrap. This automatically attempts to find the most Inner `Task` in the return type.
        Console.WriteLine("All done");
    }

Encore mieux, utilisez Task.Run Pour lancer votre opération asynchrone:

    [TestMethod]
    public async Task TestCorrect()
    {
        await Task.Run(async () => //Task.Run automatically unwraps nested Task types!
        {
            Console.WriteLine("Start");
            await Task.Delay(5000);
            Console.WriteLine("Done");
        });
        Console.WriteLine("All done");
    }
43
brz