8

我需要在我的一个函数中等待大约 25 毫秒。有时,当处理器忙于其他事情时会调用此函数,而其他时候则将处理器全部独占。

我已经尝试过time.sleep(.25),但有时它实际上是 25 毫秒,而其他时候则需要更长的时间。无论处理器可用性如何,有没有一种方法可以让您睡眠一段准确的时间?

4

7 回答 7

16

因为您使用的是抢占式操作系统,所以您无法保证您的进程能够在 25 毫秒内控制 CPU。

如果您仍然想尝试,最好有一个繁忙的循环来轮询直到 25 毫秒过去。像这样的东西可能会起作用:

import time
target_time = time.clock() + 0.025
while time.clock() < target_time:
    pass
于 2012-07-25T20:08:47.090 回答
6

0.25 秒是 250 毫秒,而不是 25 秒。除此之外,在普通操作系统上没有办法精确地等待25 毫秒——你需要一些实时操作系统。

于 2012-07-25T20:07:29.770 回答
4

你在什么系统上?如果你在 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 秒是绝对关键的。当然不要将用户端产品的优先级更改得太高。

于 2012-07-25T20:30:53.590 回答
4

编辑:在 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)
于 2017-04-19T20:00:14.777 回答
4

另一种准确计时和延迟的解决方案是使用模块时间中的 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))
于 2018-06-17T17:51:56.797 回答
2

您打算做的是一个实时应用程序。Python(可能还有您正在使用的操作系统)并非旨在对时间限制如此严格的此类应用程序进行编程。

为了实现您的目标,您需要一个 RTOS(实时操作系统)并使用合适的编程语言(通常是 C)按照 RT ​​最佳实践来开发您的应用程序。

于 2012-07-25T20:09:55.837 回答
1

从sleep 方法的文档中:

在给定的秒数内暂停执行。该参数可以是一个浮点数,以指示更精确的睡眠时间。实际的挂起时间可能少于请求的时间,因为任何捕获的信号都会在执行该信号的捕获例程后终止 sleep()。此外,由于系统中其他活动的调度,暂停时间可能比请求的时间长任意量。

事实上,这取决于您的底层操作系统。

于 2012-07-25T20:12:55.640 回答