如何在保持给定平均吞吐量的同时执行花费可变时间的操作

How to perform an operation that takes a variable amount of time while maintaining a given average throughput

我有一个函数,我想每秒调用 10 次。我从这样的代码开始:

while True:
    the_operation()
    time.sleep(1.0/TIMES_PER_SECOND)

这工作正常,但 the_operation 的调用频率略低于预期,因为需要时间自行执行操作。我们可以让代码看起来像这样:

while True:
    t = time.time()
    the_operation()
    time_to_sleep = 1.0/TIMES_PER_SECOND - (time.time() - t)
    if time_to_sleep > 0:
        time.sleep(time_to_sleep)

这样更好,但仍然不够好——没有考虑执行循环的时间,如果 the_operation 在一次迭代中恰好比 1/TIMES_PER_SECOND 花费的时间长得多,我们的吞吐量将太低。该操作平均花费不到 1/TIMES_PER_SECOND,但代码需要处理花费更长时间的情况。

以指定的平均速率调用 the_operation 的良好模式是什么?

记录您期望的时间,以查看操作是否以正确的速度执行。这将使您可以将实际时间与所需时间进行比较,如果是正数,您可以睡个好觉。如果它是负数,操作将连续 运行 不休眠,直到我们赶上。

expected = time.monotonic()
while True:
    the_operation()
    expected += 1.0/TIMES_PER_SECOND
    time.sleep(max(0, expected - time.monotonic()))

即使在循环中的任何一点发生延迟(假设操作系统决定不安排我们的进程),这也会起作用。

应使用

time.monotonic() 而不是 time.time(),因为后者受时间调整影响,而 monotonic() 始终以恒定速率单调增加,即使系统时钟已调整.

如果操作速度太慢而我们无法达到所需的吞吐量,那么收到通知可能会很有用。我们可以用这样的东西替换 sleep/max 结构:

adjust = expected - time.monotonic()
if adjust > 0:
    time.sleep(adjust)
elif adjust < -10:
    print("Can't keep up!", -adjust, "seconds behind.")