'Don't understand behavior of Tasks in C#
I'm hoping someone can help me understand what seems like some straightforward code. Clearly, I'm missing something. There are 2 things I don't understand about the behavior of this code:
If I let the code run, the last
Debug.WriteLine
for 'End Delay' never gets written. Why is this?If I put a breakpoint on the
Task.WaitAll()
line in Main(), I see thatdelayTask
has a status ofWaitingToRun
and the 'Begin Delay'Debug.WriteLine
inDoDelay()
doesn't happen, no matter how long I wait. However, as soon as I F10 over the Task.WaitAll() line, I see 'Begin Delay' show up in output. Why does a breakpoint on theTask.WaitAll()
line seem to prevent even beginning the task? This behavior doesn't change whether I useTask.WaitAll(delayTask)
orawait delayTask
.
I'm running on .NET Framework 4.6.2, unfortunately, I don't have a choice about this.
Thanks to everyone who has posted. I have an answer for the 1st question above - I changed 'async void DoDelay()' to 'async Task DoDelay()'. But I still don't have any explanation for the behavior in my 2nd question.
Update: As JonasH pointed out to me, all tasks stop when in break mode in VS.
For anyone who is interested, this article helped a lot with understanding what's going on: https://www.pluralsight.com/guides/understand-control-flow-async-await
static void Main(string[] args)
{
Debug.WriteLine($"Main-A: {DateTime.Now:mm:ss.fff}");
Task delayTask = Task.Run(() => DoDelay(10000));
Debug.WriteLine($"Main-B: {DateTime.Now:mm:ss.fff}");
Task.WaitAll(delayTask);
}
static async void DoDelay(int delayMs)
{
Debug.WriteLine($"Begin Delay: {DateTime.Now:mm:ss.fff}");
await Task.Delay(delayMs);
Debug.WriteLine($"End Delay: {DateTime.Now:mm:ss.fff}");
}
Solution 1:[1]
Task delayTask = Task.Run(() => DoDelay(10000));
This will call the method DoDelay(10000)
on a background thread, and return a task that completes when the method returns. However, DoDelay
will return at the first await
statement. The rest of the method will be run at some later time, but there is nothing that will wait for this to occur.
To fix this you should make your method return a Task, i.e. async Task DoDelay(int delayMs)
. This will not affect when the method returns, but the returned task lets you wait for the entire method to complete. This can be made more simple by using a async main method:
static async Task Main(string[] args) {
Debug.WriteLine($"Main-A: {DateTime.Now:mm:ss.fff}");
var delayTask = DoDelay(10000);
Debug.WriteLine($"Main-B: {DateTime.Now:mm:ss.fff}");
await delayTask;
Debug.WriteLine($"Main-C: {DateTime.Now:mm:ss.fff}");
}
static async Task DoDelay(int delayMs) {
Debug.WriteLine($"Begin Delay: {DateTime.Now:mm:ss.fff}");
await Task.Delay(delayMs);
Debug.WriteLine($"End Delay: {DateTime.Now:mm:ss.fff}");
}
Only use async void
when you absolutely have to, i.e. event handlers in an UI, and then make sure you are handling failures of any awaited tasks. In the vast majority of cases, use async Task
or async Task<T>
Solution 2:[2]
some Note: avoid using async void because you have to await on it to get result, So I change it to async Task
You have to use delayTask.Wait(); for waiting to complete the task.
Warning: delayTask.Wait()
is bad practice use await delayTask;
instead.
use this instead of your code I do some changes on it:
static void Main(string[] args) {
Debug.WriteLine($"Main-A: {DateTime.Now:mm:ss.fff}");
Task delayTask = Task.Run(async () => await DoDelay(10000));
Debug.WriteLine($"Main-B: {DateTime.Now:mm:ss.fff}");
delayTask.Wait();
}
static async Task DoDelay(int delayMs)
{
Debug.WriteLine($"Begin Delay: {DateTime.Now:mm:ss.fff}");
await Task.Delay(delayMs);
Debug.WriteLine($"End Delay: {DateTime.Now:mm:ss.fff}");
}
you can also use
static async Task Main(string[] args)
and remove Task.Run(async () => await DoDelay(10000));
and use await DoDelay(10000)
and await delayTask;
but it may not work it .NET framework 4.6.2
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |