[英]Run python function in one minute but exact on 00 seconds of new minute
[英]Using asyncio to run a function at the start (00 seconds) of every minute
我正在嘗試使用不同的參數同時(大約或當然)運行多個函數,並在每分鍾開始時重復。
我設法得到了一個asyncio
示例來運行,在那里我得到一個函數callback
,以使用不同的參數在特定時間運行,但我無法弄清楚如何在非常特定的時間運行它(並永遠運行它)(即我想在每分鍾開始時運行它,所以在 19:00:00、19:01:00 等等)。
Asyncio call_at
應該能夠做到這一點,但它使用的時間格式不是標准的 python 時間格式,我無法弄清楚將該時間格式指定為下一分鍾的 00 秒。
import asyncio
import time
def callback(n, loop, msg):
print(msg)
print('callback {} invoked at {}'.format(n, loop.time()))
async def main(loop):
now = loop.time()
print('clock time: {}'.format(time.time()))
print('loop time: {}'.format(now))
print('registering callbacks')
loop.call_at(now + 0.2, callback, 1, loop, 'a')
loop.call_at(now + 0.1, callback, 2, loop, 'b')
loop.call_soon(callback, 3, loop, 'c')
await asyncio.sleep(1)
event_loop = asyncio.get_event_loop()
try:
print('entering event loop')
event_loop.run_until_complete(main(event_loop))
finally:
print('closing event loop')
event_loop.close()
正如其他人所指出的,這種事情沒有內置功能,您需要自己編寫。 不過,實現起來很簡單 - 一個簡單的版本可能如下所示:
import asyncio, datetime
async def at_minute_start(cb):
while True:
now = datetime.datetime.now()
after_minute = now.second + now.microsecond / 1_000_000
if after_minute:
await asyncio.sleep(60 - after_minute)
cb()
這不使用call_later
,它是一個可以在不再需要時取消的協程。 它只是獲取當前掛鍾時間x
的秒值,然后休眠(60 - x)
以到達下一分鍾。 這是一個測試:
import time
loop = asyncio.get_event_loop()
loop.create_task(at_minute_start(lambda: print(time.asctime())))
loop.run_forever()
# output:
Wed Feb 28 21:36:00 2018
Wed Feb 28 21:37:00 2018
Wed Feb 28 21:38:00 2018
...
不幸的是,如果asyncio.sleep
碰巧睡眠時間比請求的周期短一點,例如由於時鍾偏差,那么簡單的實現可能會出錯。 在這種情況下,后續的asyncio.sleep
將嘗試再次到達同一分鍾的開始,並且只休眠幾分之一秒,從而導致回調有效地連續快速觸發兩次。 為了防止這種情況,需要額外的代碼來補償短暫的睡眠:
async def at_minute_start(cb):
now = datetime.datetime.now()
wait_for_next_minute = False
while True:
after_minute = now.second + now.microsecond / 1_000_000
if after_minute != 0:
to_next_minute = 60 - after_minute
else:
to_next_minute = 0 # already at the minute start
if wait_for_next_minute:
to_next_minute += 60
await asyncio.sleep(to_next_minute)
cb()
prev = now
now = datetime.datetime.now()
# if we're still at the same minute, our sleep was slightly
# too short, so we'll need to wait an additional minute
wait_for_next_minute = now.minute == prev.minute
就像一些評論員所說的那樣,在純 Python 中僅使用 asyncIO 沒有簡單的彈性方法來做到這一點,但是使用apscheduler庫實際上變得非常容易。
import asyncio
import datetime
import os
from apscheduler.schedulers.asyncio import AsyncIOScheduler
def tick():
print("Tick! The time is: %s" % datetime.datetime.now())
if __name__ == "__main__":
scheduler = AsyncIOScheduler()
scheduler.add_job(tick, "cron", minute="*")
scheduler.start()
print("Press Ctrl+{0} to exit".format("Break" if os.name == "nt" else "C"))
# Execution will block here until Ctrl+C (Ctrl+Break on Windows) is pressed.
try:
asyncio.get_event_loop().run_forever()
except (KeyboardInterrupt, SystemExit):
pass
沒有簡單的方法可以做到這一點。 您不能依賴loop.time()
作為“真實世界”時鍾。
唯一的解決方法是使用datetime
/ time
模塊計算loop.call_later
並使用計算的延遲調用loop.call_later
。 是的,它超級麻煩。
看看這個問題的例子: 如何使用 asyncio 定期執行函數?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.