Вот генератор, который я использую для этой цели. Можно было бы улучшить остановку через некоторое время, или вы могли бы сохранить эту логику в своем вызывающем коде или в некоторых других итераторах arround.
import time
def sleep_gen(period):
"""Generator, returning not sooner, then period seconds since last call.
returned value: time of next planned start (no need to use this value)
"""
next_time = 0
while True:
now = time.time()
sleep_time = max(next_time - now, 0)
next_time = now + sleep_time + period
time.sleep(sleep_time)
yield next_time
Вы можете использовать следующий код для проверки поведения
import plac
import time
from itertools import count, izip
import random
#sleep_gen to be defined here
@plac.annotations(
period= ("planned period for cycling in seconds (default: %(default)s)", "positional", None, float),
min_duration=("minimal real 'action' duration in seconds (default:%(default)s)", "positional", None, float),
max_duration=("maximal 'real action' duration in seconds (default:%(default)s)", "positional", None, float),
)
def main(period = 1.0, min_duration = 0.1, max_duration = 2.0):
"""Tries to start some randomly long action in regular periods"""
print """call with -h for help.
period : %(period)f
min_duration: %(min_duration)f
max_duration: %(max_duration)f""" % locals()
try:
last_time = now = time.time()
header = ( "%5s|" +"%14s|" +"%14s|" +"%8s|" +"%8s|" +"%14s|") % ("cycle", "last_time", "now", "action", "real", "next_time")
row = "%(i) 5d|%(last_time)14.2f|%(now)14.2f|%(action_dur)8.3f|%(real_dur)8.3f|%(next_time)14.2f|"
print header
action_dur = real_dur = 0.0
for i, next_time in izip(count(), sleep_gen(period)):
#we care about starting the action on time, not ending
now = time.time() #sleep_gen just tried to keep the period on schedule
real_dur = now - last_time
print row % locals()
last_time = now
#performing the "action"
action_dur = random.random() * (max_duration - min_duration) + min_duration
time.sleep(action_dur)
except KeyboardInterrupt:
print "...cancelled."
if __name__ == "__main__":
plac.call(main)
Вызов из командной строки:
$ python cycle.py
call with -h for help.
period : 1.000000
min_duration: 0.100000
max_duration: 2.000000
cycle| last_time| now| action| real| next_time|
0| 1337368558.55| 1337368558.55| 0.000| 0.002| 1337368559.55|
1| 1337368558.55| 1337368559.59| 1.042| 1.042| 1337368560.59|
2| 1337368559.59| 1337368561.32| 1.722| 1.723| 1337368562.32|
3| 1337368561.32| 1337368562.32| 0.686| 1.000| 1337368563.32|
4| 1337368562.32| 1337368563.32| 0.592| 1.000| 1337368564.32|
5| 1337368563.32| 1337368564.75| 1.439| 1.439| 1337368565.75|
6| 1337368564.75| 1337368566.08| 1.323| 1.323| 1337368567.08|
7| 1337368566.08| 1337368567.08| 0.494| 0.999| 1337368568.08|
8| 1337368567.08| 1337368568.20| 1.120| 1.121| 1337368569.20|
9| 1337368568.20| 1337368569.20| 0.572| 1.000| 1337368570.20|
10| 1337368569.20| 1337368570.20| 0.586| 1.000| 1337368571.20|
11| 1337368570.20| 1337368571.20| 0.309| 0.999| 1337368572.20|
12| 1337368571.20| 1337368572.20| 0.290| 1.000| 1337368573.20|
13| 1337368572.20| 1337368573.25| 1.052| 1.053| 1337368574.25|
14| 1337368573.25| 1337368574.25| 0.737| 1.000| 1337368575.25|
15| 1337368574.25| 1337368575.83| 1.579| 1.579| 1337368576.83|
...cancelled.
Сравнение вашего вопроса с моим ответом:
- генератор: да, это
- введите время начала: я использую только текущий момент
(что может быть тем, что часто нужно)
- введите время окончания: прекратите вызывать генератор в этот момент. Или измените генератор так, чтобы он зацикливался только на определенном количестве циклов или заканчивался в определенное время.