Python 异步IO聚集调度顺序保证

Python 异步IO聚集调度顺序保证,python,python-asyncio,Python,Python Asyncio,是否保证作为asyncio.gather参数的协同路由将 是否安排保留订单?考虑下面的例子: import asyncio async def coro(i): print('{i} finished'.format(i=i)) async def main(): await asyncio.gather( coro(0), coro(1), coro(2), coro(3),

是否保证作为
asyncio.gather
参数的协同路由将 是否安排保留订单?考虑下面的例子:

import asyncio

async def coro(i):
    print('{i} finished'.format(i=i))

async def main():
    await asyncio.gather(
            coro(0),
            coro(1),
            coro(2),
            coro(3),
            coro(4),
    )

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
结果是:

0 finished
1 finished
2 finished
3 finished
4 finished

是的,至少从cpython实现的源代码来看,它们将按顺序安排。对共同例程列表进行迭代,并为每个例程逐一向循环中添加任务。虽然我不知道在哪种情况下,调度保证变得很重要。不能保证循环会按顺序执行它们,也不能保证它们会按顺序完成。我认为这将取决于具体循环的实现细节和代码的性质。例如,在打印之前,尝试将asyncio.sleep(1)添加到co例程。

可等待的asyncio.gather(*aws,loop=None,return\u exceptions=False)

同时运行aws序列中的等待对象

如果aws中的任何等待是一个协同程序,它将自动调度 作为一项任务

如果成功完成所有等待项,则结果为 返回值的聚合列表结果值的顺序 对应于aws中可等待项的顺序。


因此,结果值的顺序是保留的,但执行顺序不是。

有一个有趣的例子,在Python3.6中,顺序至少发生了故障

让我们举一个这样的例子:

import asyncio

async def main():
    data = [1, 2, 3, 4, 5, 6, 7, 8]

    async def aiter(iterable):
        for v in iterable:
            yield v

    aiterable = aiter(data)
    aiterables = [aiterable] * 8

    values = await asyncio.gather(
        *[it.__anext__() for it in aiterables])
    
    assert values == data, f'{values} != {data}'

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Py36中的近似结果:

AssertionError: [7, 6, 3, 4, 5, 2, 8, 1] != [1, 2, 3, 4, 5, 6, 7, 8]

这种行为看起来合乎逻辑,因为协同程序是按任意顺序执行的。然而,在Py37+中,代码运行良好,输出列表顺序保持不变。我在文档中没有发现任何提及这一点的内容。

绝对不能保证它们会按特定顺序安排(或执行)。可以保证的是,传递给
gather
的等待项结果的顺序与相应的等待项相同。