首页 > 解决方案 > 开始处理异步任务,同时将它们添加到事件循环中

问题描述

asyncio 的一个常见模式,就像这里展示的那样,是将一组协程添加到列表中,然后添加asyncio.gather它们。

例如:

async def some_task(i):
    # Do something asynchronously with i

tasks = [some_task(i) for i in range(100)]

loop.run_until_complete(asyncio.gather(**tasks))

在这里,这段代码的执行顺序是在我们构建列表时没有任何任务在运行。我们将任务 1 添加到列表中,然后添加任务 2,等等,然后我们将任务 1-100 添加到事件循环中。


但是,我希望任务创建本身成为事件循环的一部分。我希望任务 1 在创建时立即安排,然后当任务在另一个线程上等待某些东西时,返回任务创建并创建任务 2 并将其添加到事件循环中。

我相信这会给我的异步代码带来更好的并发性。这可能吗?


例如,我的第一个想法是将任务创建放入协程中,并在创建任务时安排任务:

async def some_task(i):
    # Do something asynchronously with i

async def generate_tasks(loop):
    tasks = []
    for i in range(100):
        task = loop.create_task(some_task(i))
        tasks.append(loop)
    await asyncio.gather(**tasks)

loop.run_until_complete(generate_tasks())

但是,因为 my generate_tasksnever uses await,所以执行永远不会传递回事件循环,所以generate_taskswill run before的全部内容根本不会运行some_task()


但是,如果我await在创建每个任务时,它会等待每个任务完成,然后再继续下一个任务,根本不给我并发!

async def generate_tasks(loop):
    tasks = []
    for i in range(100):
        await some_task(i)

loop.run_until_complete(generate_tasks())

标签: pythonpython-asyncio

解决方案


但是,因为我generate_tasks从不使用await,所以永远不会将执行传递回事件循环

您可以使用await asyncio.sleep(0)来强制让步到里面的事件循环for。但这不太可能产生影响,创建任务/协程对确实有效。

在优化它之前,测量(用一些简单的东西,time.time好像需要)执行[some_task(i) for i in range(100)]列表理解需要多少时间。然后考虑分散该时间(可能由于增加调度开销而使完成时间更长)是否会对您的应用程序产生任何影响。结果可能会让你大吃一惊。


推荐阅读