我需要在我的一个函数中等待大约 25 毫秒。有时,当处理器忙于其他事情时会调用此函数,而其他时候则将处理器全部独占。
我已经尝试过time.sleep(.25)
,但有时它实际上是 25 毫秒,而其他时候则需要更长的时间。无论处理器可用性如何,有没有一种方法可以让您睡眠一段准确的时间?
因为您使用的是抢占式操作系统,所以您无法保证您的进程能够在 25 毫秒内控制 CPU。
如果您仍然想尝试,最好有一个繁忙的循环来轮询直到 25 毫秒过去。像这样的东西可能会起作用:
import time
target_time = time.clock() + 0.025
while time.clock() < target_time:
pass
0.25 秒是 250 毫秒,而不是 25 秒。除此之外,在普通操作系统上没有办法精确地等待25 毫秒——你需要一些实时操作系统。
你在什么系统上?如果你在 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,除非它睡眠 0.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'
0.29% 左右是相当低的开销,而且通常足够准确。
默认情况下,以前的 Windows 版本的睡眠分辨率为 55 毫秒,这意味着您的睡眠呼叫将需要 25 到 55 毫秒之间的某个时间。要将睡眠分辨率降低到 1 毫秒,您需要通过调用设置 Windows 使用的分辨率timeBeginPeriod
:
import ctypes
winmm = ctypes.WinDLL('winmm')
winmm.timeBeginPeriod(1)
另一种准确计时和延迟的解决方案是使用模块时间中的 perf_counter() 函数。在 windows 中特别有用,因为 time.sleep 以毫秒为单位不准确。请参见下面的示例,其中函数 accuracy_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))
您打算做的是一个实时应用程序。Python(可能还有您正在使用的操作系统)并非旨在对时间限制如此严格的此类应用程序进行编程。
为了实现您的目标,您需要一个 RTOS(实时操作系统)并使用合适的编程语言(通常是 C)按照 RT 最佳实践来开发您的应用程序。
从sleep 方法的文档中:
在给定的秒数内暂停执行。该参数可以是一个浮点数,以指示更精确的睡眠时间。实际的挂起时间可能少于请求的时间,因为任何捕获的信号都会在执行该信号的捕获例程后终止 sleep()。此外,由于系统中其他活动的调度,暂停时间可能比请求的时间长任意量。
事实上,这取决于您的底层操作系统。