我想编写一个程序,利用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
,但是以某种方式检查事件循环或以其他方式等待所有未完成的回调的完成?
答案 0 :(得分:1)
您可以使用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
带来的未来,并以类似于futures._chain_future
的方式将其链接到服务员。
强烈建议您在这种情况下使用自己的协程。