Asyncio 和 aiohttp 返回任务而不是结果

Asyncio and aiohttp returning task instead of results

我有一个脚本可以 运行 针对 class 中的 API 并行请求。但是,我得到的结果基本上是一项任务,而不是实际结果。有什么理由吗?

我在 https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html 上模仿了修改后的客户端代码。

import asyncio
from aiohttp import ClientSession

class Requestor:
    async def _async_request(self, url, session, sema_sz=10):
        sema = asyncio.Semaphore(sema_sz)

        async with sema:
            async with session.get(url) as response:
                req = await response.json()

        return req

    async def _async_chunk_request(self, url, chunks, headers=None, sema_sz=10):
        async with ClientSession(headers=headers) as session:
            futures = [asyncio.ensure_future(self._async_request(url.format(chunk), session, sema_sz)) for chunk in chunks]
            responses = asyncio.gather(*futures)
            await responses

    def get_request(self, url, chunks):
        loop = asyncio.get_event_loop()
        bulk_req = asyncio.ensure_future(self._async_chunk_request(url, chunks))
        loop.run_until_complete(bulk_req)

        return bulk_req

bulk_req 实际上是一个任务变量而不是结果,并在 PyCharm、Task finished coro=<Requestor._async_chunk_request() done, defined at ...

中显示

当我调试时,我发现 req 具有完整且正确的响应值,因此没有问题。感觉跟实际聚集期货有关系?

你的 _chunk_request 没有 return 任何东西。

async def _chunk_request(...):
    ...
    ...
    await responses

我制作了一个 玩具 示例,试图模仿您的过程。如果我像您一样 ended _chunk_request ,我会得到相同的结果 - 完成的任务没有结果。将 _chunk_request 更改为 return something 修复了它:

async def _chunk_request(...):
    ...
    ...
    return await responses

如果您只需要来自任务的 return 值,get_request 应该 return loop.run_until_complete() 调用的结果。


我的玩具示例

import asyncio
import random
from pprint import pprint

async def response(n):
    asyncio.sleep(random.choice([1,3,5]))
    return f'i am {n}'

async def _request(n):
    req = await response(n)
    #print(req)
    return req

async def _chunk_request(chunks):
    futures = [asyncio.ensure_future(_request(chunk)) for chunk in chunks]
    #pprint(futures)
    responses = asyncio.gather(*futures, return_exceptions=True)
    #pprint(responses)
    return await responses

def get_request(chunks):
    loop = asyncio.get_event_loop()
    bulk_req = asyncio.ensure_future(_chunk_request(chunks))
    return loop.run_until_complete(bulk_req)

In [7]: result = get_request(range(1,6))

In [8]: print(result)
['i am 1', 'i am 2', 'i am 3', 'i am 4', 'i am 5']