您看到的问题是因为您的代码每次在循环中开始每次延迟时都使用实时时间 - 因此在不定时代码中花费的时间和由于操作系统多任务处理引起的抖动会累积,从而降低整体低于你想要达到的时间。
要大大提高计时精度,请使用每个循环“应该”在应该开始后的周期 (1/sample_rate) 完成这一事实 - 并将该开始时间保持为绝对计算而不是实时,并且等到那个绝对开始时间之后的那段时间,然后时间就没有漂移了。
我把你的时间放到了timing_orig中,我使用绝对时间的修改后的代码放到了timing_new中——结果如下。
import time
def timing_orig(ratehz,timefun=time.clock):
count=0
while True:
sample_rate=ratehz
time_start=timefun()
count+=1
while (timefun()-time_start) < (1.0/sample_rate):
pass
if count == ratehz:
break
def timing_new(ratehz,timefun=time.clock):
count=0
delta = (1.0/ratehz)
# record the start of the sequence of timed periods
time_start=timefun()
while True:
count+=1
# this period ends delta from "now" (now is the time_start PLUS a number of deltas)
time_next = time_start+delta
# wait until the end time has passed
while timefun()<time_next:
pass
# calculate the idealised "now" as delta from the start of this period
time_start = time_next
if count == ratehz:
break
def timing(functotime,ratehz,ntimes,timefun=time.clock):
starttime = timefun()
for n in range(int(ntimes)):
functotime(ratehz,timefun)
endtime = timefun()
# print endtime-starttime
return ratehz*ntimes/(endtime-starttime)
if __name__=='__main__':
print "new 5000",timing(timing_new,5000.0,10.0)
print "old 5000",timing(timing_orig,5000.0,10.0)
print "new 10000",timing(timing_new,10000.0,10.0)
print "old 10000",timing(timing_orig,10000.0,10.0)
print "new 50000",timing(timing_new,50000.0,10.0)
print "old 50000",timing(timing_orig,50000.0,10.0)
print "new 100000",timing(timing_new,100000.0,10.0)
print "old 100000",timing(timing_orig,100000.0,10.0)
结果:
new 5000 4999.96331002
old 5000 4991.73952992
new 10000 9999.92662005
old 10000 9956.9314274
new 50000 49999.6477761
old 50000 49591.6104893
new 100000 99999.2172809
old 100000 94841.227219
注意我没有使用 time.sleep() 因为它引入了太多的抖动。另外,请注意,即使这个最小的示例在我的 Windows 笔记本电脑上显示了非常准确的时序(甚至高达 100khz),但如果您将更多的代码放入循环中而不是执行时间,那么时序会相应地运行缓慢。
抱歉,我使用了 Python 2.7,它没有非常方便的 time.perf_counter() 函数 - 在对 timing() 的每个调用中添加一个额外的参数 timefun=time.perf_counter()