Difference between Task.Delay () and new task (() => Thread.Sleep ())
I put together a small little demo to use a lengthy method simulated with Thread.Sleep()
and wanted to add async to go from a synchronous process to an asynchronous one. Here's the starting code:
private void button1_Click(object sender, EventArgs e)
{
LongProcess();
}
private void LongProcess()
{
for (int i = 0; i < 33; i++)
{
progressBar1.Value += 3;
Thread.Sleep(1000);
}
progressBar1.Value += 1;
}
I thought I could just change Thread.Sleep(1000)
to new Task(()=>Thread.Sleep(1000))
, for example:
private void button1_Click(object sender, EventArgs e)
{
LongProcess();
}
private async void LongProcess()
{
for (int i = 0; i < 33; i++)
{
progressBar1.Value += 3;
await new Task(()=>Thread.Sleep(1000));
}
progressBar1.Value += 1;
}
However, this never loops back after the first wait. If I change Thread.Sleep to Task.Delay everything works, but I don't understand why my code isn't working. I am guessing that something is being blocked forever, but this is not entirely clear. Can anyone please explain how my code works and a possible solution without changing Task.Delay (just so I can get a different perspective how it works)?
source to share
Task.Delay
not the same as viewing a task with Thread.Sleep
. Task.Delay
uses Timer
internally and therefore does not block the thread, however starting a new task with Thread.Sleep
blocks the thread (usually a Threadpool).
In your example, you have never run Task
. Creating a constructor Task
with a constructor will return a task Unstarted
that should be started when the method is called Start
. Otherwise, it will never finish (because you never started it).
However, calling is Task.Start
not recommended, you can call Task.Factory.StartNew(()=> Thread.Sleep(1000))
or Task.Run(()=> Thread.Sleep(1000))
if you want to waste the resource .
Also, keep in mind that StartNew is dangerous , you should prefer Task.Run
over StartNew
unless there is a compelling reason to do so.
source to share
To answer the title of the question - Task.Delay
will be canceled!
Let's look at a popular implementation using TaskCompletionSource
.
static Task Delay(int delayTime, System.Threading.CancellationToken token)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
if (delayTime < 0) throw new ArgumentOutOfRangeException("Delay time cannot be under 0");
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(p =>
{
timer.Dispose(); //stop the timer
tcs.TrySetResult(null); //timer expired, attempt to move task to the completed state.
}, null, delayTime, System.Threading.Timeout.Infinite);
token.Register(() =>
{
timer.Dispose(); //stop the timer
tcs.TrySetCanceled(); //attempt to mode task to canceled state
});
return tcs.Task;
}
You cannot do this with Thread.Sleep
. You can do it with a big old loop, but that just emulates the basic one Timer
in the code above.
source to share