Should I always use Task.Delay instead of Thread.Sleep?
There's never an advantage in replacing Thread.Sleep(1000);
in Task.Delay(1000).Wait();
. If you want to wait synchronously just use Thread.Sleep
.
If you really only have a single thread and planning to keep it that way, then you can use Thread.Sleep
. However, I would still use Task.Delay
as it's preferable in most cases and so it's a good pattern. I would only block at very top when you can't use async
anymore, and even then I would suggest using some kind of AsyncContext
.
You can also use a System.Threading.Timer
directly* instead of Task.Delay
however you should keep in mind that the timer executes every interval and doesn't wait for the actual operation to complete, so if ExternalServiceIsReady
takes more than the interval you can have multiple calls to that service concurrently.
An even better solution would be to replace the polling of the external service with an asynchronous operation so the service can notify you when it's ready instead of you asking it every second (that isn't always possible as it depends on the service):
await ExternalServiceIsReadyAsync();
* Task.Delay
uses a System.Threading.Timer
internally which also has a resolution of ~15ms.
BJ Myers
Required reading: Vexing Exceptions - Eric Lippert Why Are So Many of the Framework Classes Sealed? - Eric Lippert Making Wrong Code Look Wrong - Joel Spolsky Which is Faster? - Eric Lippert
Updated on June 05, 2022Comments
-
BJ Myers almost 2 years
I have recently seen several recommendations stating that
Thread.Sleep
should never be used in production code (most recently in this SO question). Many of these advocate for usingTask.Delay
instead. Most of the explanations I've found use UI applications as examples, since the advantages toTask.Delay
are obvious (not blocking the UI).In my case, I am using
Thread.Sleep
inside of a wait loop that polls a WCF service for a particular condition, like this:DateTime end = DateTime.UtcNow + TimeSpan.FromMinutes(2); while (DateTime.UtcNow < end) { if (ExternalServiceIsReady() == true) { return true; } Thread.Sleep(1000); }
In this case, the following potential advantages of
Task.Delay
seem not to apply:- The sleep time is fairly large relative to the typical timer resolution of around 15 ms, so the increase in accuracy of
Task.Delay
seems trivial. - The process is single-threaded (non-UI) and must block until the condition is true, so using
await
has no advantage here. - The ability to cancel the delay is not required.
Is this a case where it is appropriate to use
Thread.Sleep
? What would be the advantage (if any) of replacing my sleep line withTask.Delay(1000).Wait()
? - The sleep time is fairly large relative to the typical timer resolution of around 15 ms, so the increase in accuracy of
-
EZI about 9 yearsAnd a more better way would be if
ExternalServiceIsReady
can throw an event that way there would be no need for sleep/wait. -
i3arnon about 9 years@EZI That's asynchronous.
-
EZI about 9 yearsAnd what? doesn't it loop and sleep? What does asynchronous call change here? You only involve another task here.
-
i3arnon about 9 years@EZI An asynchronous operation means that it notifies you when it completes. It doesn't matter if it's done by competing a
Task
, invoking a callback, or raising an event. It's all the same and can be converted to other methods. -
EZI about 9 years@ i3arnon I know what an async operation is, but it seems you don't understand its usage. Replacing that line with
await ExternalServiceIsReadyAsync();
wouldn't change anything. -
i3arnon about 9 years@EZI Replacing a synchronous blocking loop with an asynchronous awaitable call would mean one less thread (and its CPU cycles) wasted.
-
Sriram Sakthivel about 9 years@i3arnon For your last comment:
Thread.Sleep
doesn't waste any cpu cycle. It keeps a usable resource(thread) hanging around, but no cpu cycles spent. Do you mean that while loop and those conditions? -
i3arnon about 9 years@SriramSakthivel
Thread.Sleep
(as doTask.Delay
) doesn't waste CPU cycles. It's the constant polling that does, and a single asynchronous operation (be itasync
or otherwise) solves that. -
Sriram Sakthivel about 9 years@i3arnon To be clear - In a constant polling still
Thread.Sleep
doesn't wastes cpu cycles; the code which does the polling does. -
i3arnon about 9 years@SriramSakthivel of course. Just as
Task.Delay
doesn't. (though if we want to nitpick,Thread.Sleep
would cause an unneeded context switch that can waste CPU cycles) -
Sriram Sakthivel about 9 yearsAnother nitpick.
Task.Delay
creates aTask
(memory allocation),task.Wait()
will spin for certain amount of time andtask.Wait()
will allocate a Kernel event after that point (kernel resource and user-> kernel transition) all of which is gonna take cpu cycles :)