Python 有没有办法阻止计时器爬行?

Python 有没有办法阻止计时器爬行?,python,timer,python-multithreading,Python,Timer,Python Multithreading,我正在寻找一种每秒运行一个方法的方法,不管它运行多长时间。在寻求帮助的过程中,我遇到了 在尝试它的过程中,发现它不能正常工作。它似乎有一个我正试图避免的问题:漂移。我试着在打印后添加一个“sleep(0.5)”,它实际上减慢了循环,并且间隔保持在1.003(大约)秒 有没有办法解决这个问题,做我想做的事 (venv) 20170728-153445 mpeck@bilbo:~/dev/whiskerlabs/aphid/loadtest$ cat a.py import threading i

我正在寻找一种每秒运行一个方法的方法,不管它运行多长时间。在寻求帮助的过程中,我遇到了

在尝试它的过程中,发现它不能正常工作。它似乎有一个我正试图避免的问题:漂移。我试着在打印后添加一个“sleep(0.5)”,它实际上减慢了循环,并且间隔保持在1.003(大约)秒

有没有办法解决这个问题,做我想做的事

(venv) 20170728-153445 mpeck@bilbo:~/dev/whiskerlabs/aphid/loadtest$ cat a.py
import threading
import time
def woof():
  threading.Timer(1.0, woof).start()
  print "Hello at %s" % time.time()
woof()
(venv) 20170728-153449 mpeck@bilbo:~/dev/whiskerlabs/aphid/loadtest$ python a.py
Hello at 1501281291.84
Hello at 1501281292.85
Hello at 1501281293.85
Hello at 1501281294.85
Hello at 1501281295.86
Hello at 1501281296.86
Hello at 1501281297.86
Hello at 1501281298.87
Hello at 1501281299.87
Hello at 1501281300.88
Hello at 1501281301.88
Hello at 1501281302.89
Hello at 1501281303.89
Hello at 1501281304.89
Hello at 1501281305.89
Hello at 1501281306.9
Hello at 1501281307.9
Hello at 1501281308.9
Hello at 1501281309.91
Hello at 1501281310.91
Hello at 1501281311.91
Hello at 1501281312.91
Hello at 1501281313.92
Hello at 1501281314.92
Hello at 1501281315.92
Hello at 1501281316.93

我敢肯定,该代码的问题在于Python需要一些时间(显然大约为.3s)来执行对函数
woof
的调用,实例化一个新的
threading.Timer
对象,并打印当前时间。因此,基本上,在您第一次调用函数并创建
threading.Timer
之后,Python会精确地等待1s,然后调用函数
woof
(大约分秒),创建一个新的
Timer
对象(至少还有一个分秒),最后以一定的延迟打印当前时间

实际上每秒运行一个程序的解决方案似乎是Twisted库,如上所述,但我自己并没有真正尝试过

编辑:我会将这个问题标记为可能的重复问题,但我显然还没有足够的声誉来做这件事。。。如果有人能友好地使用我提供的链接,那就太酷了:)

  • 如果每次都不需要新的线程,不要使用
    线程计时器;在循环中周期性地运行函数
    sleep
    (可能在一个单独的线程中)

  • 无论您使用什么方法来安排下一次执行,都不要等待您作为间隔使用的确切时间-其他语句的执行需要时间,因此结果是漂移,正如您所看到的。相反,在一个变量中写下初始时间,并在每次迭代时计算下一次您想要调度执行和睡眠的时间,以计算现在和那时的差异

    interval = 1.
    next_t = time.time()
    while True:
        next_t += interval
        time.sleep(next_t - time.time())
        # do whatever you want to do 
    
    (当然,您可以对其进行优化以获得更好的总体精度,但这至少应该避免漂移)


  • 我想知道额外的时间是否是创建新线程的时间,以及线程池执行器是否会有所帮助。我不这么认为,至少不需要一些工作。在幕后,操作系统可能需要比要求的时间更长的时间才能到达您的手中——它不会做出任何硬保证。例如,像
    time.sleep()
    这样的东西只能保证你的睡眠时间至少和你要求的一样长,而不是像你要求的那样长。在过去,我做过一些事情,比如跟踪开销,等待期望的时间减去开销。问题是,一个小问题可能会干扰事情(比如一个占用cpu太多的进程),因此需要仔细考虑才能正确处理。是的,我编写了一些代码使其休眠.995秒,但每次循环迭代它仍休眠约1.004秒:导入时间=time.time()当为True时:old=after new=old+1 now=time.time()打印(“应该睡眠”,new-now)time.sleep(new-now)after=time.time()打印(“睡眠”,after now)应该睡0.9999904643256836睡1.0031487941741943应该睡0.999992394444732666睡1.0022780895233154应该睡0.99999380111694336睡1.000175952911377这正是我在上面的评论中考虑的解决方案——可以动态地适应开销。您只需在事情失控时小心,例如
    sleep()
    由于系统中的其他活动而花费的时间远远超过预期+1.