问题
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