多个异步函数调用的结果只收集一次
如果您只需要运行一次async 函数调用序列,您可以简单地将它们立即返回的协程对象存储在一个列表中,将解压后的列表传递给asyncio.gather,然后传递给await 以收集最终返回值来自协程。
async def upper_cased(value: str) -> str:
await asyncio.sleep(1)
return value.upper()
coroutines = [
upper_cased("h"),
upper_cased("e"),
upper_cased("l"),
upper_cased("l"),
upper_cased("o"),
upper_cased(" "),
upper_cased("w"),
upper_cased("o"),
upper_cased("r"),
upper_cased("l"),
upper_cased("d"),
]
print("".join(await asyncio.gather(*coroutines)))
# prints HELLO WORLD
之所以有效,是因为与普通函数不同,调用 async 函数(无需等待)不会开始执行它,它只是返回一个对象,其中包含函数调用的所有必要细节,包括参数值。稍后可以使用此对象以不同的方式完成其执行,其中一种是使用await。
多次收集多个异步函数调用的结果
如果您需要运行相同序列的async 函数(带有预定参数)多次,只需将它们的返回值存储在一个列表中,然后将解压后的列表传递给asyncio.gather 不会工作。
这是因为协程对象只能被等待一次。当它们已经返回值时再次等待它们将引发RuntimeError。
async def random_cased(value: str) -> str:
await asyncio.sleep(1)
if random.randint(0, 1) == 1:
return value.upper()
return value.lower()
coroutines = [
random_cased("h"),
random_cased("e"),
random_cased("l"),
random_cased("l"),
random_cased("o"),
random_cased(" "),
random_cased("w"),
random_cased("o"),
random_cased("r"),
random_cased("l"),
random_cased("d"),
]
print("".join(await asyncio.gather(*coroutines)))
# prints HeLlO wOrLd (or any other random cased variation)
print("".join(await asyncio.gather(*coroutines)))
# raises RuntimeError (cannot reuse already awaited coroutine)
对于这种情况,您可以使用functools.partial 对象来存储async 函数及其参数值。
partial_funcs = [
functools.partial(random_cased, "h"),
functools.partial(random_cased, "e"),
functools.partial(random_cased, "l"),
functools.partial(random_cased, "l"),
functools.partial(random_cased, "o"),
functools.partial(random_cased, " "),
functools.partial(random_cased, "w"),
functools.partial(random_cased, "o"),
functools.partial(random_cased, "r"),
functools.partial(random_cased, "l"),
functools.partial(random_cased, "d"),
]
print("".join(await asyncio.gather(*[func() for func in partial_funcs])))
# prints HeLlO wOrLd (or any other random cased variation)
print("".join(await asyncio.gather(*[func() for func in partial_funcs])))
# prints HeLlO wOrLd (or any other random cased variation)
print("".join(await asyncio.gather(*[func() for func in partial_funcs])))
# prints HeLlO wOrLd (or any other random cased variation)
如果你愿意,你也可以使用其他容器来代替functools.partial。例如,一个用于存储函数的列表和另一个用于存储其参数的列表。