【问题标题】:How to wait for Python asyncio call_later to finish all pending如何等待 Python asyncio call_later 完成所有待处理
【发布时间】:2018-10-24 22:06:53
【问题描述】:

我想编写一个程序,利用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,但以某种方式检查事件循环或等待所有待处理回调的完成?

【问题讨论】:

    标签: python timer python-asyncio


    【解决方案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_futureloop.create_task 添加到组合中。

    添加它们确实会带来更多复杂性 - 您需要添加更多函数来获取 ensure_future 的结果,并以与 futures._chain_future 类似的方式将其与服务员链接。

    我强烈建议在这种情况下使用你自己的协程,就像你已经做过的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-27
      • 2022-01-23
      • 1970-01-01
      • 2019-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多