首页 文章

如何将coroutine添加到正在运行的asyncio循环?

提问于
浏览
18

如何为正在运行的asyncio循环添加新的协同程序? IE浏览器 . 一个已经执行了一套协同程序的程序 .

我想作为一种解决方法,可以等待现有协程完成,然后初始化一个新循环(使用附加协程) . 但有更好的方法吗?

4 回答

  • 7

    您可以使用create_task来安排新的协同程序:

    import asyncio
    
    async def cor1():
        ...
    
    async def cor2():
        ...
    
    async def main(loop):
        await asyncio.sleep(0)
        t1 = loop.create_task(cor1())
        await cor2()
        await t1
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(loop))
    loop.close()
    
  • 0

    要向已经运行的事件循环添加函数,您可以使用:

    asyncio.ensure_future(my_coro())

    在我的情况下,我使用多线程( threading )和 asyncio 并且想要将任务添加到已经运行的事件循环中 . 对于处于相同情况的任何其他人,请务必明确说明事件循环(因为 Thread 中不存在) . 即:

    在全球范围内:

    event_loop = asyncio.get_event_loop()
    

    然后,在 Thread 内:

    asyncio.ensure_future(my_coro(), loop=event_loop)
    
  • 11

    您的问题非常接近“如何向正在运行的程序添加函数调用?”

    什么时候需要在事件循环中添加新的协同程序?

    我们来看一些例子 . 这里的程序以两个协同方式并行启动事件循环:

    import asyncio
    from random import randint
    
    
    async def coro1():
        res = randint(0,3)
        await asyncio.sleep(res)
        print('coro1 finished with output {}'.format(res))
        return res
    
    async def main():
        await asyncio.gather(
            coro1(),
            coro1()
        ) # here we have two coroutines running parallely
    
    if __name__ == "__main__":
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    

    输出:

    coro1 finished with output 1
    coro1 finished with output 2
    [Finished in 2.2s]
    

    可能你需要添加一些可以获得 coro1 结果的协同程序并在它准备好后立即使用它吗?在这种情况下,只需创建等待 coro1 的coroutine并使用它的返回值:

    import asyncio
    from random import randint
    
    
    async def coro1():
        res = randint(0,3)
        await asyncio.sleep(res)
        print('coro1 finished with output {}'.format(res))
        return res
    
    async def coro2():
        res = await coro1()
        res = res * res
        await asyncio.sleep(res)
        print('coro2 finished with output {}'.format(res))
        return res
    
    async def main():
        await asyncio.gather(
            coro2(),
            coro2()
        ) # here we have two coroutines running parallely
    
    if __name__ == "__main__":
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    

    输出:

    coro1 finished with output 1
    coro2 finished with output 1
    coro1 finished with output 3
    coro2 finished with output 9
    [Finished in 12.2s]
    

    将协程视为具有特定语法的常规函数 . 你可以启动一些函数并行执行(通过 asyncio.gather ),你可以在第一次完成后启动下一个函数,你可以创建调用其他函数的新函数 .

  • 13

    这里的答案似乎都没有完全回答这个问题 . 通过让“父”任务为您执行任务,可以将任务添加到正在运行的事件循环中 . 我不确定什么是最狡猾的方式来确保父母不会结束直到它的孩子都已完成(假设这是你想要的行为),但这确实有效 .

    import asyncio
    import random
    
    
    async def add_event(n):
        print('starting ' + str(n))
        await asyncio.sleep(n)
        print('ending ' + str(n))
        return n
    
    
    async def main(loop):
    
        added_tasks = []
    
        delays = [x for x in range(5)]
    
        # shuffle to simulate unknown run times
        random.shuffle(delays)
    
        for n in delays:
            print('adding ' + str(n))
            task = loop.create_task(add_event(n))
            added_tasks.append(task)
            await asyncio.sleep(0)
    
        print('done adding tasks')
    
        # make a list of tasks that (maybe) haven't completed
        running_tasks = added_tasks[::]
    
        # wait until we see that all tasks have completed
        while running_tasks:
            running_tasks = [x for x in running_tasks if not x.done()]
            await asyncio.sleep(0)
    
        print('done running tasks')
    
        # extract the results from the tasks and return them
        results = [x.result() for x in added_tasks]
        return results
    
    
    loop = asyncio.get_event_loop()
    results = loop.run_until_complete(main(loop))
    loop.close()
    print(results)
    

相关问题