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

人走茶凉 提交于 2019-12-08 05:28:45

问题


I have a function that I want to call, say, 10 times per second. I start out with code like this:

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

This works ok but the_operation is called slightly less often than desired, because of the time to do the operation itself. We can make the code look like this instead:

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)

This is better, but still not good enough -- the time to execute the loop is not considered, and if the_operation happens to take significantly longer than 1/TIMES_PER_SECOND in one iteration, our throughput will be too low. The operation on average takes less than 1/TIMES_PER_SECOND, but the code needs to handle the cases where it does take longer.

What is a good pattern for calling the_operation at the specified rate on average?


回答1:


Keep track of the time you expect to see if operations are performed at the correct rate. This will let you compare the actual time with the desired time, and you can sleep for the difference if it's positive. If it's negative, the operations will be run continuously with no sleep until we catch up.

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

This will work even when a delay happens at any point in the loop (say the operating system decided not to schedule our process).

time.monotonic() should be used instead of time.time() because the latter is subject to time adjustments, while monotonic() always monotonically increases at a constant rate, even when the system clock is adjusted.

It may be useful to be notified if the operations are too slow and we can't achieve the desired throughput. We can replace the sleep/max construct with something like this:

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


来源:https://stackoverflow.com/questions/46352009/how-to-perform-an-operation-that-takes-a-variable-amount-of-time-while-maintaini

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!