【问题标题】:An accurate python sleep function一个准确的python sleep函数
【发布时间】:2017-12-10 01:36:50
【问题描述】:

我试过 time.sleep(),但它的准确性完全是垃圾。例如,考虑这个循环:

for i in range(10000000):
    print(i)
    sleep(.334)

观察它打印的数字。如果它像我的电脑一样,它甚至都不是正常的。这个函数应该是准确的吗?我是否在系统的某个地方发现了错误?

如果这个函数不应该是准确的,那么哪个函数会更准确?

【问题讨论】:

  • 您看到打印了哪些数字?您期望的数字是多少?
  • 打印什么数字?跑的时候没发现什么问题
  • 你想睡 1/3 秒吗?文档说明了为什么需要更长或更短的时间。 docs.python.org/3/library/time.html#time.sleep
  • 您更关心某事以特定的时间间隔准确发生(例如,程序开始后每 1/3 秒精确)还是更关心某事发生后的等待时间(例如,等待 1/3事情发生后的一秒钟)?
  • 在大多数“普通”计算机上,您不能期望操作花费精确的时间,因为操作系统有能力随时抢占您的应用程序。不仅如此,print() 也需要时间,for 循环也是如此,你不能轻易地解释(通过设计)。如果您关心精确的时间安排,您可能需要real-time computer,但您更有可能尝试解决some other problem - 请尝试问那个问题。

标签: python real-time


【解决方案1】:

如果您只是查看输出,缓冲可能会使其看起来有些抖动。您可以尝试显式刷新输出,但您也受制于显示输出的任何内容。我什至可能会猜测您在浏览器中使用 Jupyter Notebook,它还会在更新时产生大量缓冲/延迟。

另一个问题是,如果您希望每 1/3 秒运行一次,那么您将遭受累积错误的困扰。运行循环需要一点时间,打印一个值(打印需要的时间比其他部分多几个数量级),然后再次开始休眠。绕过这个的一种方法是,在你完成你想做的任何事情之后(我假设一些比计数更有趣的事情),计算直到下一个 1/3 秒的时间,并在这段时间内休眠。比如:

import random
import time

sleep_until = time.monotonic() + 1/3

for n in range(100):
    print(time.monotonic() % 100, n)
    time.sleep(random.random() / 4) # some "work"

    now = time.monotonic()
    if sleep_until > now:
        time.sleep(sleep_until - now)
    else:
        pass
        #print('task took too long')
    sleep_until += 1/3

对我来说,它给出了类似的东西:

48.34696656104643 0
48.68041984003503 1
49.08346292399801 2
49.41925806296058 3
49.72542790300213 4
50.07280854298733 5
50.41882419097237 6
50.74827564903535 7
51.08352101803757 8
51.41813271504361 9
51.75208444998134 10
52.08399672002997 11
52.41870043799281 12

所以它会反弹一点(我也在 Jupyter 中运行它,这可能会有所帮助),但不会在运行时堆积错误。

真正的问题是你想做什么

【讨论】:

  • 我正在使用的终端(xfce4-terminal)和所有喜欢它的终端都在换行符上缓冲,所以这不是问题。这些终端非常适合在收到数据时实时显示数据。
【解决方案2】:

Python 中的print 语句需要时间来运行。如果我需要 Python 程序休眠更准确的时间,我使用 datetime.timedeltawhile 循环而不是 time.sleep。这是我的代码:

from datetime import datetime, timedelta

startTime = datetime.now()
sleepTime = timedelta(seconds = 5)

# run code here

while startTime+sleepTime > datetime.now():
    pass

另外,如果您不介意将所有代码放在函数中,您可以使用装饰器函数:

from datetime import datetime, timedelta

def sleep(time):
    def outer_wrap(func):
        def wrap(*args, **kwargs):
            startTime = datetime.now()
            sleepTime = timedelta(seconds = time)
            while startTime+sleepTime > datetime.now():
                pass
            func(*args, **kwargs)
        return wrap
    return outer_wrap

@sleep(5)
def c():
    # code goes here
    pass

c()

我会推荐第一种方法,因为将所有代码放入函数中会非常低效。

注意:如果您正在执行的代码比您尝试等待的时间长,这将不起作用。它应该适用于您的情况,因为 print 花费的时间不应超过 0.334 秒。

【讨论】:

  • 打印几乎立即执行,或者至少在 50 毫秒以内。这不是问题。
  • 但是使用while 循环会显着使用大量CPU!我看到 Python 单独使用了大约 39%,当我使用 time.sleep 方法时,这是 0%(与任务管理器一样准确)!
【解决方案3】:

好的,这次我真的想通了。这不是 IO 缓冲,也不是调用 print() 或某些特定于操作系统的诡异调度巫术所花费的时间。 它一直是我的终端。(...m. night shyamalan twist...)具体来说,xfce4-terminal,虽然在尝试了大约其他七个终端之后,我发现 lxterminal 具有完全相同的问题。它们都是基于 VTE 的,但还有其他基于 VTE 的仿真器没有有问题,例如 terminatorgnome-terminal。反正我换了终端,问题就解决了。

我敢打赌,那些没有使用这两个有问题的终端中的任何一个的人都想知道我到底在说什么。

【讨论】:

    猜你喜欢
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 2010-10-27
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    相关资源
    最近更新 更多