475
votes

Are there good rule(s) for when to use Task.Delay versus Thread.Sleep?

  • Specifically, is there a minimum value to provide for one to be effective/efficient over the other?
  • Lastly, since Task.Delay causes context-switching on a async/await state machine, is there an overhead of using it?
7
10ms is a lot of cycles in computer world...Brad Christie
How fast should it be? What performance problems do you have?L.B
I think the more pertinent question is in what context do you intend to use either of these? Without that information the scope is too broad. What do you mean by effective/efficient? Are you referring to accuracy, power efficiency etc.? I'm very curious to know in what context this matters.James World
The minimum is 15.625 msec, values less than the clock interrupt rate have no effect. Task.Delay always burns up a System.Threading.Timer, Sleep has no overhead. You don't worry about overhead when you write code that does nothing.Hans Passant
something that I didn't see mentioned, but I think is important, would be that Task.Delay supports a CancellationToken, meaning you can interrupt the delay, if you, for example, are using it to slow down a cycle process. this also means your process can respond quickly when you want to cancel it . but you can achieve the same with Thread.Sleep making the sleep cycle interval shorter, and check the Token manuallay.Droa

7 Answers

458
votes

Use Thread.Sleep when you want to block the current thread.

Use Task.Delay when you want a logical delay without blocking the current thread.

Efficiency should not be a paramount concern with these methods. Their primary real-world use is as retry timers for I/O operations, which are on the order of seconds rather than milliseconds.

306
votes

The biggest difference between Task.Delay and Thread.Sleep is that Task.Delay is intended to run asynchronously. It does not make sense to use Task.Delay in synchronous code. It is a VERY bad idea to use Thread.Sleep in asynchronous code.

Normally you will call Task.Delay() with the await keyword:

await Task.Delay(5000);

or, if you want to run some code before the delay:

var sw = new Stopwatch();
sw.Start();
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;

Guess what this will print? Running for 0.0070048 seconds. If we move the await delay above the Console.WriteLine instead, it will print Running for 5.0020168 seconds.

Let's look at the difference with Thread.Sleep:

class Program
{
    static void Main(string[] args)
    {
        Task delay = asyncTask();
        syncCode();
        delay.Wait();
        Console.ReadLine();
    }

    static async Task asyncTask()
    {
        var sw = new Stopwatch();
        sw.Start();
        Console.WriteLine("async: Starting");
        Task delay = Task.Delay(5000);
        Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
        await delay;
        Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine("async: Done");
    }

    static void syncCode()
    {
        var sw = new Stopwatch();
        sw.Start();
        Console.WriteLine("sync: Starting");
        Thread.Sleep(5000);
        Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds);
        Console.WriteLine("sync: Done");
    }
}

Try to predict what this will print...

async: Starting
async: Running for 0.0070048 seconds
sync: Starting
async: Running for 5.0119008 seconds
async: Done
sync: Running for 5.0020168 seconds
sync: Done

Also, it is interesting to notice that Thread.Sleep is far more accurate, ms accuracy is not really a problem, while Task.Delay can take 15-30ms minimal. The overhead on both functions is minimal compared to the ms accuracy they have (use Stopwatch Class if you need something more accurate). Thread.Sleep still ties up your Thread, Task.Delay release it to do other work while you wait.

29
votes

if the current thread is killed and you use Thread.Sleep and it is executing then you might get a ThreadAbortException. With Task.Delay you can always provide a cancellation token and gracefully kill it. Thats one reason I would choose Task.Delay. see http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx

I also agree efficiency is not paramount in this case.

29
votes

I want to add something. Actually, Task.Delay is a timer based wait mechanism. If you look at the source you would find a reference to a Timer class which is responsible for the delay. On the other hand Thread.Sleep actually makes current thread to sleep, that way you are just blocking and wasting one thread. In async programming model you should always use Task.Delay() if you want something(continuation) happen after some delay.

1
votes

Delayed would be a better name for Task.Delay - because it doesn't delay an existing task but rather creates a new 'delayed' one which on the other hand can be awaited and can cause suspension to the current task's body. It is essentially a Timer but without a callback/body.

Awaiting a delayed task creates a new item in async message queue and doesn't block any threads. The same thread where the await is called will proceed working on other tasks should there be any, and will return to the await point after the timeout (or when the preceding items in queue are complete). Tasks under the hood use Threads - there can be many Tasks scheduled and executed in a single thread. On the other hand if you happen to call Thread.Sleep() the thread will block, i.e. it will be out of play for the amount of time asked and won't process any async messages from the queue.

In .NET there're 2 major approaches to parallelism. The old one with Threads, ThreadPools etc. And the new one, based on Tasks, async/await, TPL. As a rule of thumb you don't mix APIs from these two universes.

0
votes

It is also worth to mention that Thread.Sleep(1) will fire GC faster.

This is purely based mine & team member observations. Lets assume that you have service which creates new task every for specific request (approx. 200-300 ongoing) and this task contains many weak references in flow. The task is working like state machine so we were firing the Thread.Sleep(1) on change state and by doing so we managed to optimize utilization of memory in the application - like I said before - this will makes GC to fire faster. It doesn't make so much difference in low memory consumption services (<1GB).

-4
votes

My opinion,

Task.Delay() is asynchronous. It doesn't block the current thread. You can still do other operations within current thread. It returns a Task return type (Thread.Sleep() doesn't return anything ). You can check if this task is completed(use Task.IsCompleted property) later after another time-consuming process.

Thread.Sleep() doesn't have a return type. It's synchronous. In the thread, you can't really do anything other than waiting for the delay to finish.

As for real-life usage, I have been programming for 15 years. I have never used Thread.Sleep() in production code. I couldn't find any use case for it. Maybe that's because I mostly do web application development.