await Task.Delay() vs. Task.Delay().Wait()

122,415

The second test has two nested tasks and you are waiting for the outermost one, to fix this you must use t.Result.Wait(). t.Result gets the inner task.

The second method is roughly equivalent of this:

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");
}

By calling t.Wait() you are waiting for outermost task which returns immediately.


The ultimately 'correct' way to handle this scenario is to forgo using Wait at all and just use await. Wait can cause deadlock issues once you attached a UI to your async code.

    [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");
    }

Even better just use Task.Run to kick off your asynchronous operation:

    [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");
    }
Share:
122,415
svenskmand
Author by

svenskmand

Updated on November 08, 2020

Comments

  • svenskmand
    svenskmand over 3 years

    In C# I have the following two simple examples:

    [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");
    }
    

    The first example creates a task that prints "Start", waits 5 seconds prints "Done" and then ends the task. I wait for the task to finish and then print "All done". When I run the test it does as expected.

    The second test should have the same behavior, except that the waiting inside the Task should be non-blocking due to the use of async and await. But this test just prints "Start" and then immediately "All done" and "Done" is never printed.

    I do not know why I get this behavior :S Any help would be appreciated very much :)

  • svenskmand
    svenskmand over 9 years
    Thanks that worked :) By the way is it always okay to use Task.Run instead of Task.Factory.StartNew or are there cases where I would need Task.Factory.StartNew that Task.Run cannot handle? :)
  • Daniel Leiszen
    Daniel Leiszen over 3 years
    Task.Run(someAction); is a convenience wrapper and equivalent to Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);