首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python协程中的并行异步IO

Python协程中的并行异步IO
EN

Stack Overflow用户
提问于 2017-11-08 08:10:29
回答 1查看 13K关注 0票数 23

简单的示例:我需要并行发出两个不相关的HTTP请求。最简单的方法是什么?我希望是这样的:

代码语言:javascript
复制
async def do_the_job():
    with aiohttp.ClientSession() as session:
        coro_1 = session.get('http://httpbin.org/get')
        coro_2 = session.get('http://httpbin.org/ip')
        return combine_responses(await coro_1, await coro_2)

换句话说,我希望启动IO操作并等待它们的结果,这样它们就可以有效地并行运行。这可以通过asyncio.gather来实现

代码语言:javascript
复制
async def do_the_job():
    with aiohttp.ClientSession() as session:
        coro_1 = session.get('http://example.com/get')
        coro_2 = session.get('http://example.org/tp')
        return combine_responses(*(await asyncio.gather(coro_1, coro_2)))

接下来,我想要一些复杂的依赖结构。我希望在具备所有先决条件的情况下开始操作,并在需要结果时获得结果。这有助于asyncio.ensure_future从由事件循环单独管理的协程中分离出任务:

代码语言:javascript
复制
async def do_the_job():
    with aiohttp.ClientSession() as session:
        fut_1 = asyncio.ensure_future(session.get('http://httpbin.org/ip'))
        coro_2 = session.get('http://httpbin.org/get')
        coro_3 = session.post('http://httpbin.org/post', data=(await coro_2)
        coro_3_result = await coro_3
        return combine_responses(await fut_1, coro_3_result)

为了在我的逻辑流程中使用协程实现并行非阻塞IO,我必须使用asyncio.ensure_futureasyncio.gather (实际上使用asyncio.ensure_future),这是真的吗?有没有一种不那么“冗长”的方法?

通常情况下,开发人员必须考虑哪些协程应该成为单独的任务,并使用上述功能来获得最佳性能,这是真的吗?

在事件循环中使用没有多个任务的协程有意义吗?

在现实生活中,事件循环任务有多“重”?当然,它们比操作系统线程或进程“更轻”。我应该在多大程度上努力使这类任务的数量降到最低?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-11-08 13:52:37

我需要并行地发出两个不相关的

请求。最简单的方法是什么?

代码语言:javascript
复制
import asyncio
import aiohttp


async def request(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.text()


async def main():
    results = await asyncio.gather(
        request('http://httpbin.org/delay/1'),
        request('http://httpbin.org/delay/1'),
    )
    print(len(results))


loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
    loop.run_until_complete(loop.shutdown_asyncgens())
finally:
    loop.close()

可以,您可以使用asyncio.gather实现并发,也可以使用asyncio.ensure_future创建任务。

下一步,我想要一些复杂的依赖结构?我希望在具备所有先决条件的情况下开始操作,并在需要结果时获得结果。

虽然您提供的代码可以完成工作,但在不同的协程上拆分并发流并再次使用asyncio.gather会更好

代码语言:javascript
复制
import asyncio
import aiohttp


async def request(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.text()


async def get_ip():
    return await request('http://httpbin.org/ip')


async def post_from_get():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://httpbin.org/get') as resp:
            get_res = await resp.text()
        async with session.post('http://httpbin.org/post', data=get_res) as resp:
            return await resp.text()


async def main():
    results = await asyncio.gather(
        get_ip(),
        post_from_get(),
    )
    print(len(results))


loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
    loop.run_until_complete(loop.shutdown_asyncgens())
finally:
    loop.close()

通常开发人员必须考虑哪些协程应该成为单独的任务,并使用上述功能来获得最佳性能,这是真的吗?

既然你使用异步,你可能想要并发运行一些作业来提高性能,对吧?asyncio.gather是一种方式--“并发运行这些作业,以更快地获得结果”。

如果您不必考虑应该并发运行哪些作业来获得性能,那么您可以使用普通同步代码。

在事件循环中使用没有多个任务的协程有意义吗?

在您的代码中,如果您不需要,则不必手动创建任务:此答案中的两个片段都不使用asyncio.ensure_future。但在内部,asyncio经常使用任务(例如,正如您所提到的,asyncio.gather使用任务本身)。

在现实生活中,事件循环任务有多“重”?当然,它们比操作系统线程或进程“更轻”。我应该在多大程度上努力使这类任务的数量降到最低?

异步程序的主要瓶颈是(几乎总是)网络:你根本不应该担心异步协同程序/任务的数量。

票数 24
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47169474

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档