我需要在一个函数中等待大约25毫秒。有时候当处理器正在处理其他任务时,这个函数会被调用,另一些情况下则独占整个处理器。
我尝试使用time.sleep(.25)
,但有时候它实际上只是25毫秒,而其他时候则需要更长时间。是否有一种方法可以精确地睡眠一段时间,而不考虑处理器的可用性?
因为你正在使用一种抢占式操作系统,所以无法保证你的进程能够在25毫秒内控制CPU。
如果你仍想尝试,最好使用一个忙循环来轮询直到25毫秒的时间已过。类似这样的代码可能有效:
import time
target_time = time.clock() + 0.025
while time.clock() < target_time:
pass
time.sleep
暂停25毫秒,线程将被从活动队列中取出,直到过去了25毫秒,然后它将被移回到活动队列,并在未来的某个时间点执行。如果你使用忙等待,你会一直保持在活动队列上。 - Sam Mussmanntarget_time
:target_time += 0.025
,而不是target_time = time.clock() + 0.025
。这样,你就不会在等待之间“浪费”时间了。 - Lay Gonzáleztime.clock()
已被替换为time.perf_counter()
。 - Dogkiller870.25秒等于250毫秒,不是25毫秒。除此之外,在普通操作系统上没有办法精确地等待仅仅 25 毫秒 – 你需要一些实时操作系统。
编辑:在Windows 10中,这种鬼扯似乎是不必要的。试试这样做:
>>> from time import sleep
>>> import timeit
>>> '%.2f%% overhead' % (timeit.timeit('sleep(0.025)', number=100, globals=globals()) / 0.025 - 100)
'0.29% overhead'
大约29%或如此的数字,相当低的开销,通常足够准确。
之前的Windows版本默认的睡眠分辨率为55毫秒,这意味着您的睡眠调用需要花费25到55毫秒。要将睡眠分辨率降至1毫秒,您需要通过调用timeBeginPeriod
设置Windows使用的分辨率:
import ctypes
winmm = ctypes.WinDLL('winmm')
winmm.timeBeginPeriod(1)
另一个准确计时和延迟的解决方案是使用time模块中的perf_counter()函数。在Windows操作系统中特别有用,因为time.sleep在毫秒级别上不够精确。请参见下面的示例,其中accurate_delay函数创建了毫秒级别的延迟。
import time
def accurate_delay(delay):
''' Function to provide accurate time delay in millisecond
'''
_ = time.perf_counter() + delay/1000
while time.perf_counter() < _:
pass
delay = 10
t_start = time.perf_counter()
print('Wait for {:.0f} ms. Start: {:.5f}'.format(delay, t_start))
accurate_delay(delay)
t_end = time.perf_counter()
print('End time: {:.5f}. Delay is {:.5f} ms'.
format(t_end, 1000*(t_end - t_start)))
sum = 0
ntests = 1000
for _ in range(ntests):
t_start = time.perf_counter()
accurate_delay(delay)
t_end = time.perf_counter()
print('Test completed: {:.2f}%'.format(_/ntests * 100), end='\r', flush=True)
sum = sum + 1000*(t_end - t_start) - delay
print('Average difference in time delay is {:.5f} ms.'.format(sum/ntests))
您所使用的操作系统是什么?如果您使用的是Windows,您可能希望按照以下方式进行精确计时:
import ctypes
kernel32 = ctypes.windll.kernel32
# This sets the priority of the process to realtime--the same priority as the mouse pointer.
kernel32.SetThreadPriority(kernel32.GetCurrentThread(), 31)
# This creates a timer. This only needs to be done once.
timer = kernel32.CreateWaitableTimerA(ctypes.c_void_p(), True, ctypes.c_void_p())
# The kernel measures in 100 nanosecond intervals, so we must multiply .25 by 10000
delay = ctypes.c_longlong(.25 * 10000)
kernel32.SetWaitableTimer(timer, ctypes.byref(delay), 0, ctypes.c_void_p(), ctypes.c_void_p(), False)
kernel32.WaitForSingleObject(timer, 0xffffffff)
这段代码将几乎保证您的进程将会休眠0.25秒。但要注意,除非绝对必要,否则您可能需要将优先级降低到2或3。对于用户端产品,千万不要将优先级设置得太高。
从文档的sleep方法中:
暂停执行给定的秒数。参数可以是浮点数,以指示更精确的睡眠时间。实际的暂停时间可能会比请求的时间少,因为任何捕获的信号都将在执行该信号的捕获例程后终止sleep()。此外,由于系统中其他活动的调度,暂停时间可能会比请求的时间长。
事实上,这取决于您的底层操作系统。
sleep
非常适合完成这项任务。 - Karoly Horvath