4

需要考虑的应用类型是示波器或高速数据记录器。我有一个检索所需信息的函数,我只需要弄清楚如何一遍又一遍地调用它,非常快速且高精度。

time.sleep() 有限制,我不认为这是要走的路。

我已经研究了内置的事件调度程序,但我认为它不够精确,也不能完全满足我的需求。

对此的要求是:

  • 高速采样。10ms 是最多的。
  • 高精度间隔。在 10ms 时,10% 的误差是可以接受的 (±1ms)。
  • 相当低的 CPU 使用率,在 10 毫秒时可以接受一些负载,但对于 100 毫秒或更长时间的间隔,它应该小于 ~5%。我知道这是主观的,我想我的意思是占用 CPU 是不可接受的。
  • 理想情况下,定时器将使用间隔时间初始化,然后在需要时启动。然后应以正确的时间间隔一遍又一遍地调用所需的函数,直到计时器停止。
  • 它只会(不是必须)在 Windows 机器上运行。

是否有任何现有的库可以满足这些要求?我不想重新发明轮子,但如果必须,我可能会使用 Windows 多媒体计时器 (winmm.dll)。对此有何评论/建议?

4

2 回答 2

7

我知道我回答自己的问题迟到了,但希望它会对某人有所帮助。

我为 Windows 多媒体计时器编写了一个包装器,纯粹是为了测试。它似乎运行良好,但代码没有经过全面测试,也没有经过优化。

mmtimer.py:

from ctypes import *
from ctypes.wintypes import UINT
from ctypes.wintypes import DWORD

timeproc = WINFUNCTYPE(None, c_uint, c_uint, DWORD, DWORD, DWORD)
timeSetEvent = windll.winmm.timeSetEvent
timeKillEvent = windll.winmm.timeKillEvent


class mmtimer:
    def Tick(self):
        self.tickFunc()

        if not self.periodic:
            self.stop()

    def CallBack(self, uID, uMsg, dwUser, dw1, dw2):
        if self.running:
            self.Tick()

    def __init__(self, interval, tickFunc, stopFunc=None, resolution=0, periodic=True):
        self.interval = UINT(interval)
        self.resolution = UINT(resolution)
        self.tickFunc = tickFunc
        self.stopFunc = stopFunc
        self.periodic = periodic
        self.id = None
        self.running = False
        self.calbckfn = timeproc(self.CallBack)

    def start(self, instant=False):
        if not self.running:
            self.running = True
            if instant:
                self.Tick()

            self.id = timeSetEvent(self.interval, self.resolution,
                                   self.calbckfn, c_ulong(0),
                                   c_uint(self.periodic))

    def stop(self):
        if self.running:
            timeKillEvent(self.id)
            self.running = False

            if self.stopFunc:
                self.stopFunc()

定期测试代码:

from mmtimer import mmtimer
import time

def tick():
    print("{0:.2f}".format(time.clock() * 1000))

t1 = mmtimer(10, tick)
time.clock()
t1.start(True)
time.sleep(0.1)
t1.stop()

以毫秒为单位的输出:

0.00
10.40
20.15
29.91
39.68
50.43
60.19
69.96
79.72
90.46
100.23

一键测试代码:

from mmtimer import mmtimer
import time

def tick():
    print("{0:.2f}".format(time.clock() * 1000))

t1 = mmtimer(150, tick, periodic=False)
time.clock()
t1.start()

以毫秒为单位的输出:

150.17

从结果中可以看出,它非常准确。然而,这只是使用time.clock(),所以带上一小撮盐。

在使用 10 毫秒定期计时器的长时间测试期间,我的旧双码 3GHz 机器上的 CPU 使用率约为 3% 或更少。该机器似乎也在空闲时使用它,所以我想说额外的 CPU 使用率是最小的。

于 2013-05-01T08:36:23.850 回答
2

编辑:写完下面的东西后,我倾向于为 python 事件调度程序实现类似的测试。我不明白你为什么认为它不够准确。

像下面这样的东西似乎在我的 Linux 下运行得很好(我没有理由认为它不适用于 Windows)。每 10 毫秒on_timer_event()调用一次,根据实时时钟打印自上次调用以来的时间。这显示了计时器的大致精度。最后,打印出总时间以显示没有漂移。

下面的代码似乎存在一个问题,事件偶尔会以虚假(和短时间间隔)出现。我不知道为什么会这样,但毫无疑问,通过一些游戏你可以让它变得可靠。我认为这种方法是要走的路。

import pygame
import time

pygame.init()
TIMER_EVENT = pygame.USEREVENT+1

pygame.time.set_timer(TIMER_EVENT, 10)

timer_count = 0
MAX_TIMER_COUNT = 1000

def on_timer_event():
    global last_time
    global timer_count

    new_time = time.time()

    print new_time - last_time
    last_time = new_time

    timer_count += 1

    if timer_count > MAX_TIMER_COUNT:
        print last_time - initial_time
        pygame.event.post(pygame.event.Event(pygame.QUIT, {}))

initial_time = time.time()
last_time = initial_time
while True:
    event = pygame.event.wait()
    if event.type == TIMER_EVENT:
        on_timer_event()

    elif event.type == pygame.QUIT:
        break
于 2012-05-23T11:26:39.990 回答