为什么我们需要将 [] 添加到可迭代数组并将 * 添加到 asyncio.gather?

Why do we need to add [] to a iterable array and * to asyncio.gather?

使用这个例子

import time
import asyncio


async def main(x):
    print(f"Starting Task {x}")
    await asyncio.sleep(3)
    print(f"Finished Task {x}")


async def async_io():
    tasks = []
    for i in range(10):
        tasks += [main(i)]
    await asyncio.gather(*tasks)

if __name__ == "__main__":
    start_time = time.perf_counter()
    asyncio.run(async_io())
    print(f"Took {time.perf_counter() - start_time} secs")

我注意到我们需要创建一个列表来跟踪要完成的任务。可以理解,但是为什么我们要在 main(i) 函数上添加 [] 包装器呢?而且在 asyncio.gather(*tasks) 中,为什么我们也需要在那里添加星号?

why do we add the [] wrapper over the main(i) function?

有几种方法可以将项目添加到列表中。一种这样的方式,即您选择的方式,是将两个列表连接在一起。

>>> [1] + [2]
[1, 2]

尝试连接列表和其他内容将导致 TypeError

在您的特定情况下,您使用的是增强赋值,一个(通常性能更高的)shorthand for

tasks = tasks + [main(i)]

另一种方法是使用 append

tasks.append(main(i))

如果您的真实代码与您的示例代码匹配,拼写所有这些的更好方法是

tasks = [main(i) for i in range(10)]

in the asyncio.gather(*tasks), why do we need to add the asterisk there as well?

因为 gather 将 运行 它接收到的每个位置参数。对 gather 的调用应该类似于

asyncio.gather(main(0))

asyncio.gather(main(0), main(1))

由于有时您需要使用可变数量的位置参数,Python 提供了解包运算符(* 在列表的情况下)。

如果您愿意,您的示例可以重写为

async def async_io():
    await asyncio.gather(*[main(i) for i in range(10)])