代码之家  ›  专栏  ›  技术社区  ›  Jason R. Coombs

如何等待Python asyncial call_稍后完成所有挂起的操作

  •  0
  • Jason R. Coombs  · 技术社区  · 6 年前

    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 是一个定制的合作项目。

    是否可以使用事件循环的 ,但以某种方式检查事件循环或等待所有挂起的回调的完成?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Bharel    6 年前

    你可以用 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()
    

    待会儿打电话给你 用于正常函数而不是协程。如果 say_hi ensure_future loop.create_task 加入混音。

    添加它们确实会带来更多的复杂性-您需要添加更多的函数 确保未来 的结果,并以类似的方式与你的服务员连锁 futures._chain_future .

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