12

I was playing around with the time.sleep function from python's standard library and found it inadequate for sub-ms delays. From testing I found it to actually wait 1.1-1.2 ms for a 1ms wait. Implementing a busy wait got the accuracy to within 1%. I used:

def busy_wait(dt):   
    current_time = time.time()
    while (time.time() < current_time+dt):
        pass

and could get down to 0.0001 seconds before breaking 1% accuracy.

The main questions I have are:

  • Why is the sleep function so inaccurate (possibly a C issue)? Will getting a better CPU with a higher clock speed change this?
  • Why would anyone use sleep? The only advantage I see, power conservation, is limited to embedded systems, no?
  • Would it be viable to compensate for sleep's inaccuracy with calibration? Like so:
def sleep(dt):
    sleep(calibration_function(dt))

As an aside, I read that sleep doesn't even function well with long wait times: Upper limit in Python time.sleep()? I also read somewhere on SO of making a loop of shorter time intervals to increase precision, but that is useless when I want to delay 0.01 sec. Karl Voigtland mentions using ctypes' nanosleep, but I feel this is overkill and that time.sleep should do it's intended behavior.

time.sleep is a broken python feature? Or does nobody care about accurate time measurement enough?

Community
  • 1
  • 1
JDong
  • 2,304
  • 3
  • 24
  • 42
  • 1
    possible duplicate of [How accurate is python's time.sleep()?](http://stackoverflow.com/questions/1133857/how-accurate-is-pythons-time-sleep) – g19fanatic Jan 15 '14 at 19:30
  • Yea I figured it was an OS call, but now I'm wondering why they use an OS call when a busy wait is better. – JDong Jan 30 '14 at 18:57
  • a busy wait sucks down CPU time and blocks a cpu. A sleep does a context switch and doesn't block other execution (it does 'block' your execution). In general you only busy wait if you really do need the exact timing, and even then you're still limited to the OSes need for CPU which may context you away anyways... – g19fanatic Jan 30 '14 at 20:22
  • Also of general interest may be question ["How can I get the Windows system time with millisecond resolution?"](http://stackoverflow.com/q/3729169/2419207) and article ["Windows Timer Resolution: Megawatts Wasted"](http://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/) – iljau Jan 30 '14 at 23:08
  • @JDong: Busy waiting is not better in the general case because the OS can preempt your program at *any time*. Thus, any sleeping strategy under the sun can be arbitrarily bad depending on CPU load and scheduler fickleness. – Kevin Nov 28 '14 at 23:17

2 Answers2

10

On Windows the OS Sleep function (which Python necessarily uses) can only wake up a thread on a multiple of the current timer interval. Typically this ranges between 1.0 ms and 15.6 ms. Lowering the timer interval can be handy because it allows for shorter sleeps, but it wastes electricity, as I wrote about in this article:

http://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/

Busy waiting may give better accuracy but is generally a horrible idea since it wastes even more electricity and steals CPU time from more deserving tasks:

https://randomascii.wordpress.com/2012/06/05/in-praise-of-idleness/

Finally, the accuracy of busy waiting will depend on what timer function you are using to get the current time, and may also depend on the timer interval:

https://randomascii.wordpress.com/2013/05/09/timegettime-versus-gettickcount/

Why do you want to sleep for such short time periods? Usually it would be better to wait for something to happen -- waiting on an event -- rather than waiting for such short time periods.

Bruce Dawson
  • 3,284
  • 29
  • 38
  • In fact Python `time.sleep()` uses a `WaitForSingleObject()` call with a timeout to catch any Ctrl-C during waiting (via `SetConsoleCtrlHandler()` that signals an event.) – schlenk Nov 28 '14 at 23:27
  • The application is a sort of macro; I have a set of actions I want to simulate very accurately. I've learned how to do this in C, but have not yet found the canonical solution in Python. My question is a bit unanswerable, so I will accept your answer for now. Thanks for the insight. – JDong Nov 29 '14 at 04:14
  • @schlenk Thanks for the information about the implementation of time.sleep(). The rules about when the timeout can expire are basically the same as for Sleep() (because the scheduler only runs when something happens or when a timer interrupt fires) so the answer still applies. – Bruce Dawson Nov 30 '14 at 01:36
0

This is sort of a duplicate question, but I'll try to answer it here anyway to the best of my ability.

The sleep function is an OS call that differs from busy wait in that it doesn't block the thread. If you have a multi-threaded script though, it shouldn't block the other threads. The sleep function is inaccurate in Windows because it is not a realtime OS (not sure what that means). If you are looking strictly for accuracy of the wait, busy wait is the way to go. Otherwise, time.sleep() is probably preferred. The reason the OS call to sleep is inaccurate is probably because it relies on the OS to return at the correct time, and is reliant on the precision of the OS's scheduler.

JDong
  • 2,304
  • 3
  • 24
  • 42