You can use apscheduler to achieve this. There are a number of setups you can do to do this, depending on your exact use case. For example, splitting each item as its own job:
import time
from datetime import datetime, timedelta
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.interval import IntervalTrigger
class Item:
def __init__(self, name):
self.name = name
def make_request(self):
print(f"{datetime.now()}: {self.name}")
items = [
Item(name="Item0"),
Item(name="Item1"),
Item(name="Item2"),
]
scheduler = BlockingScheduler() # blocks the main thread
for i, item in enumerate(items):
scheduler.add_job(item.make_request,
IntervalTrigger(minutes=len(items)), # every item is executed once per minute
next_run_time=datetime.now() + timedelta(minutes=i), # delay items execution by a minute
)
scheduler.start()
Sample output:
2021-01-19 23:27:27.926250: Item0
2021-01-19 23:28:27.928920: Item1
2021-01-19 23:29:27.924316: Item2
2021-01-19 23:30:27.927307: Item0
2021-01-19 23:31:27.927305: Item1
2021-01-19 23:32:27.931385: Item2
If the make_request
takes more minutes to finish than there are items, it's possible to re-trigger the job once it finishes or else allowing concurrent executions of the same job. Another possibility is to schedule jobs using CRON triggers instead of using the next_run_time
delay.
If you absolutely want items to be synchronised, then you can have a single job running every minute with max_instances=len(items)
, & maintaining flags to see which item is currently running. However, this may be prone to race conditions & in general, more mechanical code is required.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…