await Task.Delay() vs. Task.Delay().Wait()
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");
}
svenskmand
Updated on November 08, 2020Comments
-
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 over 9 yearsThanks 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 over 3 yearsTask.Run(someAction); is a convenience wrapper and equivalent to Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);