【问题标题】:Limit loop to N iterations per minute将循环限制为每分钟 N 次迭代
【发布时间】:2013-07-24 06:12:09
【问题描述】:

有人可以帮我在 Python 中将循环限制为每分钟 N 次迭代。

假设我有

limit = 5
for items in recvData:
     # > limit iterations in past minute? -> sleep for 60 seconds from last iterations before proceeding? #
     ... do work ...

我将如何进行时间检查/睡眠以提供正确的流程。我不担心在等待时阻塞正在执行的线程/进程。

谢谢

【问题讨论】:

  • 您打算在循环中完成什么类型​​的工作?

标签: python


【解决方案1】:

需要注意的是,这不是“硬实时”代码。由于操作系统调度等原因,这将略微关闭。话虽如此,除非您知道您需要硬实时,否则就足够了。

import time

limit = 5
starttime = time.time()
for i, item in enumerate(recvData):
    if not i + 1 % limit:
        sleeptime =starttime + 60 - time.time()
        if sleeptime > 0:
            time.sleep(sleeptime)
        starttime = time.time()
    #processing code

【讨论】:

  • 谢谢,但是如果我在处理代码下放置一个“打印项目”,整个数组就会在那里打印,而不是打印 5 然后等待 60 秒再继续。
  • @Jason。您没有说要分组打印它们。这将按照您的要求一次处理一个。当您打印出列表时,当然会打印整个数组。
  • @AaronMcSmooth:为此,您需要正确估计 limit s.t。 limit * iterationTime <= 1 min 并且在整个执行过程中都必须如此。
  • @AaronMcSmooth - 但 items 只是每次迭代的 recvData 列表的一个元素?因此,每次迭代都会打印一个元素,并且每分钟应该有 n 次迭代。很抱歉,如果我感到困惑。
  • @pszilard。我专门构造了它,所以我不这样做。它执行五次迭代并然后计算剩余的睡眠时间。计算这个不需要迭代时间。我需要那个估计 iff 我希望五次迭代均匀分布在一分钟的时间间隔内,这是 OP 没有指定的另一件事。
【解决方案2】:

使用itertools recipes 中的grouper,并结合时间检查。

import itertools, datetime, time
limit = 5

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.izip_longest(fillvalue=fillvalue, *args)

for items in grouper(limit, recvData):
    prev_minute = datetime.datetime.now().minute

    for item in items:
        # do stuff

    _, _, _, _, minute, second, _ = datetime.datetime.now()
    if minute == prev_minute:
        time.sleep( 60 - second )

【讨论】:

  • 谢谢,这失败了:TypeError: 'datetime.datetime' object is not iterable
  • 同AaronMcSmooth,你需要知道limit,并且非常了解它:)
  • @pszilard。 katrialex 采取了与我相同的策略,并在开始时执行所有五个,然后然后计算剩余的睡眠时间。
【解决方案3】:

这在很大程度上取决于您在循环内执行的工作类型以及您希望该机制工作的准确程度。

ATM 我可以想出两种可能的方案:

  • 如果一次迭代所花费的时间大约是恒定的,那么您可以计算前几次迭代的平均值,然后“休眠”1 - iterationTime
  • 否则,您可以轮询时间并重新计算每一步(或几步)的平均值。

根据您的单循环执行时间的标准偏差,两种方案都可以很好地工作,但如果执行时间变化很大,它们都不会。此外,如果您想要均匀分布的循环周期,并且不仅要保持平均值/分钟,您还必须分配 sleep-s 并在每次迭代后执行一次。

我对 Python 不够熟悉,不知道查询时间的成本有多大,以及睡眠时可能会出现哪些其他 Python 特定的问题。

【讨论】:

    【解决方案4】:

    这将是最合适的答案: What's a good rate limiting algorithm?

    我特别喜欢使用装饰器的第二个答案!

    【讨论】: