Search code examples
c#multithreadingasynchronousthread-sleep

Difference between Task.Delay() and new Task(()=>Thread.Sleep())


I was putting together a small little demo to take a long running method simulated with a Thread.Sleep() and wanted to add async to easily go from a synchronous process to an async one. Here's the initial 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 was thinking I could simply change the Thread.Sleep(1000) into a new Task(()=>Thread.Sleep(1000)), like so:

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 returns to the loop after the first await. If I change the Thread.Sleep to a Task.Delay everything works, but I don't understand why my code doesn't work. I assume something is getting blocked forever, but it doesn't quite make sense. Can anyone explain how my code works, and a possible solution without changing to Task.Delay (just so I can get another perspective of how this works)?


Solution

  • Task.Delay isn't same as staring a Task with Thread.Sleep. Task.Delay uses Timer internally and thus it doesn't blocks any thread, however starting a new Task with Thread.Sleep blocks the thread (typically Threadpool thread).

    In your example you never started the Task. Creating a Task with constructor will return a Unstarted task needs to be started with a call to Start method. Otherwise it will never complete(because you never started it).

    However calling Task.Start is discouraged, You can call Task.Factory.StartNew(()=> Thread.Sleep(1000)) or Task.Run(()=> Thread.Sleep(1000)) if you want to waste a resource.

    Also, be aware that StartNew is dangerous, you should prefer Task.Run over StartNew unless there's a compelling reason to do so.