[英]How to wait for Python asyncio call_later to finish all pending
我想編寫一個程序,該程序利用call_later來發信號通知某事(或事物)稍后發生,它們本身可能會添加更多要調用的例程,然后發信號通知該程序運行,直到沒有剩余要運行的東西為止。 例如,我可以執行以下操作:
import asyncio
START_RATE = 1
async def say_hi(who):
print(f'hello {who}')
async def call_later(t, func, *params):
await asyncio.sleep(t)
await func(*params)
def run():
# Let's go!
incr = START_RATE
loop = asyncio.get_event_loop()
tasks = []
for x in range(5):
wait_delta = 5 - x
tasks.append(
call_later(incr * wait_delta, say_hi, x)
)
loop.run_until_complete(asyncio.gather(*tasks))
run()
但是您會注意到call_later
是定制的協程。
是否可以使用事件循環的call_later
,但是以某種方式檢查事件循環或以其他方式等待所有未完成的回調的完成?
您可能會使用asyncio.all_tasks()進行內省,但這可能是錯誤的方法。
正確的方法是創建期貨並允許call_later
將其標記為已完成:
import asyncio
from functools import partial
START_RATE = 1
def say_hi(who):
print(f'hello {who}')
def run_on_finish(callback):
def wrapper(func, *args, **kwargs):
try:
return func(*args, **kwargs)
finally:
callback()
return wrapper
def release_waiter(waiter, *args):
"""Taken from standard library"""
if not waiter.done():
waiter.set_result(None)
def run():
# Let's go!
incr = START_RATE
loop = asyncio.get_event_loop()
tasks = []
for x in range(5):
wait_delta = 5 - x
# Create a waiter
waiter = loop.create_future()
release_cb = partial(release_waiter, waiter)
# Schedule the function, making sure we release the waiter on finish
handle = loop.call_later(incr * wait_delta, run_on_finish(release_cb),
say_hi, x)
# If waiter is cancelled, cancel the handle too.
waiter.add_done_callback(lambda *args: handle.cancel)
tasks.append(waiter)
loop.run_until_complete(asyncio.gather(*tasks))
run()
請記住, call_later
用於常規功能而非協程。 如果say_hi
需要成為協程,則應在混合中添加ensure_future
或loop.create_task
。
如果把它們也確實會帶來更多的並發症-你需要添加更多的功能,從而利用ensure_future
的產生的未來,並用類似的方式,以你的服務員IT連鎖futures._chain_future
。
我已經強烈建議您在這種情況下使用自己的協程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.