Windows 10/11下time.sleep毫秒级休眠不准,求替代方案
毫秒级休眠替代方案(Windows平台)
问题背景
我需要让函数每秒运行约200次(允许±50次误差),但使用time.sleep(0.005)时实际休眠时间远长于预期。这是Windows 10/11的特有问题,官方无意修复。测试空循环代码:
last_time = time.time() counter = 0 while True: now = time.time() if now - last_time >= 1: print(counter) last_time = now counter = 0 counter += 1
台式机输出约64-65,笔记本约70,远达不到目标频率。
可行替代方案
1. 调用系统API提升定时器分辨率
Windows默认定时器分辨率约15.6ms,这是time.sleep精度差的核心原因。可以用pywin32库修改分辨率:
import time import win32api # 设置定时器分辨率为1ms(最小可设0.5ms,依系统支持调整) win32api.timeBeginPeriod(1) try: last_time = time.time() counter = 0 while True: # 执行你的函数逻辑 counter += 1 now = time.time() # 计算需休眠的剩余时间 sleep_time = 0.005 - (now - last_time) if sleep_time > 0: time.sleep(sleep_time) if now - last_time >= 1: print(counter) last_time = now counter = 0 finally: # 必须恢复系统默认分辨率,避免影响其他程序 win32api.timeEndPeriod(1)
2. 用内置ctypes调用系统API(无需额外安装库)
不想装pywin32的话,用内置ctypes直接调用winmm.dll:
import time import ctypes winmm = ctypes.WinDLL('winmm.dll') winmm.timeBeginPeriod(1) try: last_time = time.time() counter = 0 while True: counter += 1 now = time.time() sleep_time = 0.005 - (now - last_time) if sleep_time > 0: time.sleep(sleep_time) if now - last_time >= 1: print(counter) last_time = now counter = 0 finally: winmm.timeEndPeriod(1)
3. 短休眠+忙等待结合
不想修改系统定时器的话,先休眠大部分时间,最后用忙等待补全剩余时间(会占用更多CPU):
import time last_time = time.time() counter = 0 while True: counter += 1 now = time.time() target_time = last_time + 0.005 # 先休眠大部分时长,留0.001秒用忙等待 sleep_time = target_time - now - 0.001 if sleep_time > 0: time.sleep(sleep_time) # 忙等待到目标时间点 while time.time() < target_time: pass if now - last_time >= 1: print(counter) last_time = now counter = 0
4. 使用threading.Timer调度周期性任务
如果是周期性执行函数,结合调整后的定时器分辨率,用threading.Timer能获得更稳定的频率:
import threading import time import win32api win32api.timeBeginPeriod(1) counter = 0 last_time = time.time() def task(): global counter, last_time counter += 1 now = time.time() if now - last_time >= 1: print(counter) last_time = now counter = 0 # 调度下一次任务 threading.Timer(0.005, task).start() task() try: while True: time.sleep(1) finally: win32api.timeEndPeriod(1)
内容的提问来源于stack exchange,提问作者Subversion1
相关产品推荐
相关产品推荐

