假设我们有一个虚拟函数:
async def foo(arg):
result = await some_remote_call(arg)
return result.upper()
有什么区别:
import asyncio
coros = []
for i in range(5):
coros.append(foo(i))
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(coros))
和:
import asyncio
futures = []
for i in range(5):
futures.append(asyncio.ensure_future(foo(i)))
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(futures))
_注意_:该示例返回结果,但这不是问题的重点。当返回值很重要时,使用 gather()
而不是 wait()
。
无论返回值如何,我都在寻找 ensure_future()
的清晰度。 wait(coros)
和 wait(futures)
都运行协程,那么什么时候以及为什么应该将协程包装在 ensure_future
中?
基本上,使用 Python 3.5 的 async
运行一堆非阻塞操作的正确方法 ™ 是什么?
对于额外的信用,如果我想批量调用怎么办?例如,我需要调用 some_remote_call(...)
1000 次,但我不想用 1000 个并发连接压垮 Web 服务器/数据库/等。这对于线程或进程池是可行的,但是有没有办法用 asyncio
来做到这一点?
2020 年更新(Python 3.7+) :不要使用这些片段。而是使用:
import asyncio
async def do_something_async():
tasks = []
for i in range(5):
tasks.append(asyncio.create_task(foo(i)))
await asyncio.gather(*tasks)
def do_something():
asyncio.run(do_something_async)
还可以考虑使用 Trio ,这是 asyncio 的强大的第三方替代方案。
原文由 knite 发布,翻译遵循 CC BY-SA 4.0 许可协议
Vincent 的评论链接到 https://github.com/python/asyncio/blob/master/asyncio/tasks.py#L346 ,这表明
wait()
将协程包装在ensure_future()
为你!换句话说,我们确实需要一个未来,协程会默默地转化为它们。
当我找到关于如何批处理协程/期货的明确解释时,我会更新这个答案。