【问题标题】:How do I ensure that a Python while-loop takes a particular amount of time to run?如何确保 Python while 循环需要特定的时间才能运行?
【发布时间】:2012-11-02 14:56:37
【问题描述】:

我正在使用 while 循环读取串行数据。但是,我无法控制采样率。

代码本身似乎需要 0.2 秒才能运行,所以我知道我不会比这更快。但我希望能够精确控制采样的速度。

我觉得我可以使用“睡眠”来做到这一点,但问题是循环本身在不同点可能需要更长的时间来读取(具体取决于通过串行数据传输的内容),所以代码必须弥补余额。

例如,假设我想每 1 秒采样一次,并且循环需要 0.2 秒到 0.3 秒的时间来运行。我的代码需要足够聪明才能休眠 0.8 秒(如果循环需要 0.2 秒)或 0.7 秒(如果循环需要 0.3 秒)。

import serial
import csv
import time

#open serial stream
    while True:

        #read and print a line
        sample_value=ser.readline()
        sample_time=time.time()-zero
        sample_line=str(sample_time)+','+str(sample_value)
        outfile.write(sample_line)
        print 'time: ',sample_time,', value: ',sample_value

【问题讨论】:

  • 在使用 /dev/rtc 作为异步反应器中的触发器之前,我已经做过这种事情。它以与测量时间无关的精确间隔触发。但你也可以只使用 itimer。

标签: python python-2.7 while-loop serial-port pyserial


【解决方案1】:

只需测量运行代码所花费的每次循环迭代的时间,并相应地sleep

import time

while True:
    now = time.time()            # get the time
    do_something()               # do your stuff
    elapsed = time.time() - now  # how long was it running?
    time.sleep(1.-elapsed)       # sleep accordingly so the full iteration takes 1 second

当然不是 100% 完美(有时可能会缩短一毫秒或更多),但我想这已经足够了。


另一个不错的方法是使用twistedLoopingCall

from twisted.internet import task
from twisted.internet import reactor

def do_something():
    pass # do your work here

task.LoopingCall(do_something).start(1.0)
reactor.run()

【讨论】:

    【解决方案2】:

    一个相当优雅的方法是你在 UNIX 上工作:使用信号库

    代码:

    import signal
    
    
    def _handle_timeout():
        print "timeout hit" # Do nothing here
    
    def second(count):
        signal.signal(signal.SIGALRM, _handle_timeout)
        signal.alarm(1)
        try:
            count += 1 # put your function here
            signal.pause()
    
        finally:
            signal.alarm(0)
            return count
    
    
    if __name__ == '__main__':
    
        count = 0
        count = second(count)
        count = second(count)
        count = second(count)
        count = second(count)
        count = second(count)
    
        print count
    

    还有时间:

     georgesl@cleese:~/Bureau$ time python timer.py
     5
    
     real   0m5.081s
     user   0m0.068s
     sys    0m0.004s
    

    但有两个警告:它只适用于 *nix,而且它不是多线程安全的。

    【讨论】:

      【解决方案3】:

      在循环开始时检查是否经过了适当的时间。如果还没有,sleep

      # Set up initial conditions for sample_time outside the loop
      sample_period = ???
      next_min_time = 0
      while True:
          sample_time = time.time() - zero
          if sample_time < next_min_time:
              time.sleep(next_min_time - sample_time)
              continue
          # read and print a line
          sample_value = ser.readline()
          sample_line = str(sample_time)+','+str(sample_value)
          outfile.write(sample_line)
          print 'time: {}, value: {}'.format(sample_time, sample_value)
          next_min_time = sample_time + sample_period
      

      【讨论】:

      • 您正在用一个空白循环来填充等待时间。而是使用time.sleep() 来允许调度程序通过处理其他线程/进程来填充等待时间。
      猜你喜欢
      • 2019-10-12
      • 1970-01-01
      • 1970-01-01
      • 2016-12-12
      • 1970-01-01
      • 1970-01-01
      • 2016-02-25
      • 2013-10-11
      • 1970-01-01
      相关资源
      最近更新 更多