Python3.5中协程和未来/任务之间的区别?

2022-03-25 00:00:00 python python-3.x python-asyncio

问题描述

假设我们有一个伪函数:

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中包装协同例程?

基本上,使用Python3.5的async运行一系列非阻塞操作的正确方式(Tm)是什么?

要获得额外的积分,如果我想要批处理呼叫,该怎么办?例如,我需要调用some_remote_call(...)1000次,但我不想同时使用1000个连接来粉碎Web服务器/数据库/等。使用线程或进程池可以做到这一点,但有没有办法使用asyncio实现这一点?

2020更新(Python3.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,这是一种强大的第三方异步解决方案。


解决方案

文森特的评论链接到https://github.com/python/asyncio/blob/master/asyncio/tasks.py#L346,显示wait()为您包装了ensure_future()中的协程!

换句话说,我们确实需要一个未来,协程将悄悄地转化为它们。

当我找到有关如何批处理协程/期货的明确解释时,我将更新此答案。

相关文章