Thread.Sleep for less than 1 millisecond
Asked Answered
D

6

42

I want to call thread sleep with less than 1 millisecond. I read that neither thread.Sleep nor Windows-OS support that.

What's the solution for that?

For all those who wonder why I need this: I'm doing a stress test, and want to know how many messages my module can handle per second. So my code is:

 // Set the relative part of Second hat will be allocated for each message 
 //For example: 5 messages - every message will get 200 miliseconds 
 var quantum = 1000 / numOfMessages;

 for (var i = 0; i < numOfMessages; i++)
 {
      _bus.Publish(new MyMessage());
      if (rate != 0) 
          Thread.Sleep(quantum);
 }

I'll be glad to get your opinion on that.

Dahlberg answered 6/6, 2011 at 15:57 Comment(4)
Why do you want to do that? The solution is probably to approach your problem in a more suitable way. ;-)Carleton
If it's not supported by the OS then no, you cannot. Why do you want to do this?Hesterhesther
and what is purpose of this if I may ask?Internecine
You can't do this; Thread.Sleep will almost always yield execution of your thread, and you cannot control or predict when the OS decides to schedule it again. Sleeping precise amounts of time is impossible on a non-realtime OS.Caithness
G
53

You can't do this. A single sleep call will typically block for far longer than a millisecond (it's OS and system dependent, but in my experience, Thread.Sleep(1) tends to block for somewhere between 12-15ms).

Windows, in general, is not designed as a real-time operating system. This type of control is typically impossible to achieve on normal (desktop/server) versions of Windows.

The closest you can get is typically to spin and eat CPU cycles until you've achieved the wait time you want (measured with a high performance counter). This, however, is pretty awful - you'll eat up an entire CPU, and even then, you'll likely get preempted by the OS at times and effectively "sleep" for longer than 1ms...

Grader answered 6/6, 2011 at 16:0 Comment(8)
For others coming to this thread, I tested to verify with Mono C# under linux/ubuntu using Thread.Sleep(1), it sleeps the thread for precisely 1ms.Pyroxenite
Vista and newer support tickless scheduling. If the hardware supports this, the kernel can schedule below 1ms, but sleep is limited to 1ms. Remember, sleep is only guaranteed to sleep for at least that amount of time, but no guarantees when the thread will wake up.Revet
I hate this answer. It's technically correct with regards to sleeping, but as far as what the OP and most people want there is a brute-force but very effective solution by Sam below. The high upvotes and firm "You can't do this" on this answer dissuades people from scrolling down and finding their solution.Indo
@Indo The entire last paragraph is describing the technique mentioned below - which, as I say, still doesn't necessarily work properly (as you can get preempted), though it does allow for more precision. That being said, SpinWait is a better approach than the one below if that's what you're doing - see learn.microsoft.com/en-us/dotnet/api/…Grader
@ReedCopsey I don't think just spinning directly solves the issue either, it's the use of the stopwatch in Sam's answer that makes it spot on.Indo
@Indo you need both, ideally. Spinning is better than a while loop, but you need the SW for timing. That being said, you can still be preempted, so it's not a real solution, just an approximation that eats cpu.Grader
I recently solved that (kind of) by just spinning until Stopwatch.ElapsedTicks match the desired time. It works surprisingly well and I used it for simulating asynchronous data provider. 1ms worked slower than my typical network download, so I set my own WaitAsync() that allowed to specify times like 0.1ms. Now it behaves more like real dl, even with irregular speed ;) It's next to useless if you want precise delay, but when +/- 50% is fine, then this is perfect.Culinary
I recently found when having Thread.Sleep(1) in dotnet core 6 app runs on linux amd64, it actually sleeps exactly 1 second. Of course on Windows machines, it still sleeps between 2-15 ms.Jegger
A
33

The code below will most definitely offer a more precise way of blocking, rather than calling Thread.Sleep(x); (although this method will block the thread, not put it to sleep). Below we are using the StopWatch class to measure how long we need to keep looping and block the calling thread.

using System.Diagnostics;

private static void NOP(double durationSeconds)
{
    var durationTicks = Math.Round(durationSeconds * Stopwatch.Frequency);
    var sw = Stopwatch.StartNew();

    while (sw.ElapsedTicks < durationTicks)
    {

    }
}

Example usage,

private static void Main()
{
    NOP(5); // Wait 5 seconds.

    Console.WriteLine("Hello World!");

    Console.ReadLine();
}
Aaron answered 6/3, 2014 at 11:32 Comment(8)
The question is explicitly asking for how to sleep for less than 1ms. This answer will block instead of sleep. Because the question is about a stress test it might be good enough in this instance so am up-voting it anyway.Heterochromatic
Good point. Forgot to mention that in my post, just updated it now.Aaron
For coolness, you could also add var sw = Stopwatch.StartNew(); Less one line of code :)Antiquarian
Nice, I wasn't aware of that.Aaron
How long is a tick here, 100 nanoseconds ? Is this consistent on every machine ?Cystitis
@Cystitis According to this post, the duration of a tick is dependant on the OS/hardware. However, you can use the Stopwatch's Frequency property to determine the exact length of a tick on your machine.Aaron
This worked for me. Reading all the stuff about unavoidable latency. Im my case I needed to count to a number in a certain amount of time (500 ms) for a dmx lighting program. Thread.Sleep did indeed add 12-15ms per trip. so trip took 750ms.. When using this, the loop executes in 510ms! Just divide by 1000 to get msLebbie
The old days time simulator in DOS will tell you that this won't work if someone press the "TURBO" button @Aaron is right. This definitely wont work AND where is less than 1ms?Vita
C
13

Why?
Usually there are a very limited number of CPUs and cores on one machine - you get just a small number if independent execution units.

From the other hands there are a number of processes and many more threads. Each thread requires some processor time, that is assigned internally by Windows core processes. Usually Windows blocks all threads and gives a certain amount of CPU core time to particular threads, then it switches the context to other threads.

When you call Thread.Sleep no matter how small you kill the whole time span Windows gave to the thread, as there is no reason to simply wait for it and the context is switched straight away. It can take a few ms when Windows gives your thread some CPU next time.

What to use?
Alternatively, you can spin your CPU, spinning is not a terrible thing to do and can be very useful. It is for example used in System.Collections.Concurrent namespace a lot with non-blocking collections, e.g.:

SpinWait sw = new SpinWait();
sw.SpinOnce();
Climb answered 7/6, 2011 at 1:13 Comment(0)
P
8

Most of the legitimate reasons for using Thread.Sleep(1) or Thread.Sleep(0) involve fairly advanced thread synchronization techniques. Like Reed said, you will not get the desired resolution using conventional techniques. I do not know for sure what it is you are trying to accomplish, but I think I can assume that you want to cause an action to occur at 1 millisecond intervals. If that is the case then take a look at multimedia timers. They can provide resolution down to 1ms. Unfortunately, there is no API built into the .NET Framework (that I am aware of) that taps into this Windows feature. But you can use the interop layer to call directly into the Win32 APIs. There are even examples of doing this in C# out there.

Pean answered 6/6, 2011 at 18:10 Comment(0)
S
6

In the good old days, you would use the "QueryPerformanceTimer" API of Win32, when sub milisecond resolution was needed.

There seems to be more info on the subject over on Code-Project: http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx

This won't allow you to "Sleep()" with the same resolution as pointed out by Reed Copsey.

Edit: As pointed out by Reed Copsey and Brian Gideon the QueryPerfomanceTimer has been replaced by Stopwatch in .NET

Socialism answered 6/6, 2011 at 16:2 Comment(4)
This doesn't block - it just gives you a way to measure. The Stopwatch class effectively does this in C# (by using QueryPerformanceCounter internally).Grader
No, but it provides a reference of time with higher resolution. I have no idea what Erez is up to, but i reckon he could approach his problem differently, using the performance-timer (Edit: StopWatch, did'nt know that one, thanks) instead...Socialism
+1: Yes, this is a reasonable approach. Except I would mention Stopwatch instead of QueryPerformanceCounter.Pean
Thanks Brian, Yes I totally agree that Stopwatch should be used instead. I'll put that in my reponse.Socialism
L
2

I was looking for the same thing as the OP, and managed to find an answer that works for me. I'm surprised that none of the other answers mentioned this.

When you call Thread.Sleep(), you can use one of two overloads: An int with the number of milliseconds, or a TimeSpan.

A TimeSpan's Constructor, in turn, has a number of overloads. One of them is a single long denoting the number of ticks the TimeSpan represents. One tick is a lot less than 1ms. In fact, another part of TimeSpan's docs gave an example of 10000 ticks happening in 1ms.

Therefore, I think the closest answer to the question is that if you want Thread.Sleep for less than 1ms, you would create a TimeSpan with less than 1ms worth of ticks, then pass that to Thread.Sleep().

Ligation answered 28/8, 2022 at 4:48 Comment(2)
I found when trying to do this, any time less than 1ms isn't actually waited. Examples: Thread.Sleep(Timespan.FromTicks(9999)); = no delay Thread.Sleep(Timespan.FromTicks(10000)); = delay over 1 msIcosahedron
Indeed, this is possible - a timespan less than 1ms is accepted. However, the behavior of the code is the same as if you used Thread.Sleep(0) - (0 ms). So this answer does not practically resolve the OP's needs. I'd suggest you to clarify this side effectRobby

© 2022 - 2024 — McMap. All rights reserved.