Task.Delay() not behaving as expected or rather I'm not understanding what it is supposed to do. I'm trying to get my head around Task
s in C# and how to replace Thread
s in my implementation.
What I'm trying to do is something like this:
I've got that implemented with Threads fine, but all cool kids say I should be using Task, and don't touch Thread.
So for the code I have this (Ignore [Test]
- this just a convenient way to try out things)
[Test]
public void ChattyTask()
{
var chattyTask = new Task(ChattyWriter);
chattyTask.Start();
chattyTask.Wait();
}
public void ChattyWriter()
{
int count = 0;
while (true)
{
var message = String.Format("Chatty Writer number {0}", count);
Trace.WriteLine(message);
count++;
Task.Delay(1000);
if (count >= 20)
{
break;
}
}
}
When I run this, the test finishes in milliseconds, not in 20 seconds as I would expect. If I replace Task.Delay()
with Thread.Sleep()
, everything works as expected and I get the printout once a second. I have tried adding async
and await
into ChattyWriter()
, but not only it did not add a 1 second delay, it only printed only one line instead of 20.
What am I doing wrong?
Probably It'll help to describe what I'm doing: my project works with external API (RESTful) and after I request some tasks to happen, I need to poll the API to check if the task has been completed. External tasks can be long running: 1-15 minutes. So I need some delay between checking for completion. And there could be many different concurrent processes executed with multiple external tasks. I understand, that if I use Thread.Sleep()
when polling, other processes on the same Thread
will be blocked for no good reason.
Note that since the task that calls the Delay method executes asynchronously, the parent task must wait for it to complete by using the await keyword.
Task. Delay() is asynchronous. It doesn't block the current thread. You can still do other operations within current thread.
Delay(1000) doesn't block the thread, unlike Task. Delay(1000). Wait() would do, more details.
If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.
Task.Delay
returns a Task
object on which you have to wait. Otherwise the following code will be executed immediately. Therfore you have to declare your method as async
. Then you can await Task.Delay
public async Task ChattyWriter()
{
int count = 0;
while (true)
{
var message = String.Format("Chatty Writer number {0}", count);
Trace.WriteLine(message);
count++;
await Task.Delay(1000);
...
}
}
You have to interrupt your calling thread somehow. The unit test would terminate and the background thread as well. But if you call this method from the UI, the UI will not get blocked.
By calling Wait
on an asynchronous method you will end up with a deadlock. See here for more information.
Task.Delay(1000);
creates an async task that will complete after a second, but the execution of the current method will continue in parallel.
In order to wait for the task to complete first, you could replace
Task.Delay(1000);
with
Task.Delay(1000).Wait();
Task.Delay() actually creates a task, so you just need to wait for it.
Try this
public static void ChattyWriter()
{
int count = 0;
while (true)
{
var message = String.Format("Chatty Writer number {0}", count);
Console.WriteLine(message);
count++;
var t = Task.Delay(1000);
t.Wait();
if (count >= 20)
{
break;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With