异步收集调度订单保证

时间:2019-02-13 11:05:18

标签: 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),
            coro(4),
    )

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

和结果:

0 finished
1 finished
2 finished
3 finished
4 finished

3 个答案:

答案 0 :(得分:6)

From Python documentation

可等待的asyncio.gather(* aws,loop = None,return_exceptions = False)

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

如果aws中有待等待的协程,则会自动安排 作为任务。

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

因此保留了结果值的顺序,但没有保留执行顺序。

答案 1 :(得分:1)

是的,至少从cpython实现的源代码中,将按顺序安排它们。迭代协程序列表,并将任务逐一添加到循环中。尽管我看不到在哪种情况下,计划保证变得很重要。不能保证循环将按顺序执行它们,也不能保证它们将按该顺序完成。我认为这将取决于特定循环的实现细节和代码的性质。例如,尝试在打印之前将asyncio.sleep(1)添加到协同例程中。

答案 2 :(得分:0)

在一个有趣的极端情况下,至少在Python 3.6中,顺序中断了。

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

WAR

Py36的近似结果:

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())

此行为看起来合乎逻辑,因为AssertionError: [7, 6, 3, 4, 5, 2, 8, 1] != [1, 2, 3, 4, 5, 6, 7, 8] 协程以任意顺序执行。但是,在Py37 +中,代码可以正常工作,并且保留输出列表顺序。我在文档中没有找到任何提及。