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())
答案 0 :(得分:1)
但是,由于我的
generate_tasks
从未使用过await
,因此执行从未传递回事件循环
您可以使用await asyncio.sleep(0)
强制让步到for
内部的事件循环。但这不太可能有所作为,创建任务/协程对确实非常有效。
在对此进行优化之前,请测量(必要时使用time.time
这样的简单内容)执行[some_task(i) for i in range(100)]
列表理解需要花费多少时间。然后考虑分散该时间(由于增加调度时间而可能需要较长的时间才能完成)对于您的应用程序是否会有所不同。结果可能会让您感到惊讶。