开始处理异步任务,同时将其添加到事件循环中

时间:2018-06-26 14:34:50

标签: python python-asyncio

asyncio的一种常见模式(如here所示)是将一组协程添加到列表中,然后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())

但是,由于我的generate_tasks从未使用过await,因此执行从未传递回事件循环,因此整个generate_tasks都将在some_task()运行之前运行全部。


但是,如果我在创建每个任务时await,它将在继续执行下一个任务之前等待每个任务完成,完全没有并发性!

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

loop.run_until_complete(generate_tasks())

1 个答案:

答案 0 :(得分:1)

  

但是,由于我的generate_tasks从未使用过await,因此执行从未传递回事件循环

您可以使用await asyncio.sleep(0)强制让步到for内部的事件循环。但这不太可能有所作为,创建任务/协程对确实非常有效。

在对此进行优化之前,请测量(必要时使用time.time这样的简单内容)执行[some_task(i) for i in range(100)]列表理解需要花费多少时间。然后考虑分散该时间(由于增加调度时间而可能需要较长的时间才能完成)对于您的应用程序是否会有所不同。结果可能会让您感到惊讶。