Why time.sleep() is so slow in Windows?
Asked Answered
I

1

7

I'm looping 1000 times with time delay 1ms and calculating total time. It's very interesting how the total time is 15.6 seconds instead of 1. When I opened Google Chrome and surfed some websites, it ran correctly with 1 sec total. Also, it ran fine with Macbook too. I'm wondering what kind of solutions that I need to do to fix this problem? Please try to run it without Chrome opened an again with Chrome opened to see the difference. It ran normally when Quora or Reddit or Stackoverflow opened on my system.

from timeit import default_timer as timer
import time
start = timer()
for i in range(1000):
    time.sleep(0.001)

end = timer()
print ("Total time: ", end - start)

Edit: I didn't run it on Python. I just opened up Chrome and browsed some websites to speed up the time delay.

Updated: It's about the timer resolution from Windows. So basically, Chrome changed the timer resolution from 15.6ms to 1ms. This article explains very well: https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/

It answered 14/11, 2016 at 17:33 Comment(11)
How are you running python in chrome? This is very confusing.Edmonton
Your mistake is assuming that sleep(0.001) will sleep for exactly a millisecond, rather than just at least 1ms. You might want to read stackoverflow.com/questions/9518106Fridlund
To Eli: I didn't run it on Python. I just opened up Chrome and browsed some websites to speed up the time delay. Sorry for the confusion.It
@IkerHua: why would that increase the time delay?Weeden
-Jon: I understand it won't be exactly a millisecond. But the uncertainty is huge. When I ran it when Chrome is opened, it took 1.003 second to loop 1000 times. When Chrome is not opened, it took 15.6 seconds to loop 1000 times. And there's no modification in code between those two trials. That's what confused me the most.It
@MartijnPieters: Honestly, I have no clue. It's just very weird. Basically speaking, the program runs as expected when Chrome is opened. Otherwise, it would run extremely slow. And it only happens on Windows systems, both laptop (win 7) and desktop (win 10).It
@IkerHua: sounds like you have an interrupt issue; Chrome does a lot of I/O.Weeden
Looks like the Windows sleep implementation is indeed interrupt based.Weeden
@MartijnPieterst: I read the link provided by Jon above, and it talked about the timer resolution. And it seems like Chrome did activate the 1ms resolution. Otherwise, its default value is ~15 or 16ms. That's why I got 1 when Chrome is on and 15.6 when Chrome is off.It
@MartijnPieters: That's a very good article. Thanks man!!! Now I need to figure out how to increase the timing resolution from the OS.It
@IkerHua Instead, just check the time before you call sleep.Lagrange
I
9

I finally figured it out. Thanks a lot for the comments. Those gave me hints to solve it. To explain why this happened, Windows OS has its default timer resolution set to 15.625 ms or 64 Hz, which is decently enough for most of the applications. However, for applications that need very short sampling rate or time delay, then 15.625 ms is not sufficient. Therefore, when I ran my program itself, it's stuck at 15.6 s for 1000 points. However, when Chrome is opened, the higher resolution timer is triggered and changed to 1 ms instead of 15.6, which caused my program to run as expected.

Therefore, in order to solve it, I needed to call a Windows function named timeBeginPeriod(period) to change the resolution timer. Fortunately, python made it easy for me to fix it by providing ctypes library. The final code is provided below:

from time import perf_counter as timer
import time
from ctypes import windll #new

timeBeginPeriod = windll.winmm.timeBeginPeriod #new
timeBeginPeriod(1) #new

start = timer()
for i in range(1000):
    print (i)
    time.sleep(0.001)

end = timer()
print ("Total time: ", end - start)

Warning: I read about how this high timer resolution will affect the overall performance and also the battery. I have not seen anything happening yet, and CPU Usage on Activity on Windows Task Manage doesn't seem to overwhelming either. But keep that in mind if your applications happen to cause some strange behaviors.

It answered 14/11, 2016 at 20:58 Comment(5)
A cleaner implementation with error checking and context management. Of course, this is really unreliable for anything critical because it's at the mercy of other software running on the system. If you need critical timing you're better of busy looping with time.perf_counter() rather than relying on the system scheduler.Jessee
@eryksun: Hi eryksun, thank you for your suggestion. Would your method guarantee the exact time delay per cycle? Mine is still off by 0.1 or 0.2 milliseconds, and it's kind of bad because my application is to plot points at constant rate. Just a bit off from the rate would make the plot look really bad.It
On Windows, timer.perf_counter calls QueryPerformanceCounter, which is a monotonic clock with at least 1 microsecond resolution. Check time.get_clock_info('perf_counter').Jessee
I read and figured that timer.perf_counter is very powerful and accurate. But how do you use time.perf_counter() to delay or sleep in python? My understanding is it can be used to measure the time difference only.It
A "sleep" necessarily involves the kernel scheduler, which puts you at the mercy of the system timer resolution. If you need precision, then simply loop for the period of time, e.g. deadline = time.perf_counter() + period; while time.perf_counter() < deadline: pass.Jessee

© 2022 - 2024 — McMap. All rights reserved.