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)?

+3


source to share


3 answers


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.

+6


source


new Task(()=>Thread.Sleep(1000))

creates a task but does not start it.



You can use Task.Run(() => Thread.Sleep(1000))

or Task.Factory.StartNew(() => Thread.Sleep(1000))

to create and run a task.

+4


source


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.

+3


source







All Articles