【问题标题】:aiohttp RuntimeError: await wasn't used with futureaiohttp RuntimeError: await 未与未来一起使用
【发布时间】:2021-04-11 20:50:40
【问题描述】:

我知道python asyncio - RuntimeError: await wasn't used with future,但是那里的答案并没有解决这里发生的事情。

使用aiohttp时遇到以下错误:

  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/selector_events.py", line 485, in sock_connect
    return await fut
RuntimeError: await wasn't used with future
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7fb28040f760>

这是相关的代码:

urls = # some list of URLs including `https://www.alphavantage.co/query?function=OVERVIEW&symbol=IBM&apikey=demo`.....

async def run_tasks():
    session = aiohttp.ClientSession()
    tasks = [session.get(url) for url in urls]
    await asyncio.gather(*tasks)
    await session.close()

asyncio.run(run_tasks())

看起来就像我正在正确地等待事件循环,但我一直遇到这个问题,这是什么原因?

版本:

aiohttp==3.7.4.post0
asyncio==3.4.3
Python 3.8.0

【问题讨论】:

  • 我尝试通过添加import asyncio, aiohttp 并将urls 定义为urls = ['https://example.com'] 来重现您的问题。对我来说,脚本运行完成没有错误。你能用that code重现这个问题吗?你能在不同的计算机或不同的 Python 安装上重现它吗?
  • 试试:http://example.com/
  • 我试过了,行为是一样的——脚本完成没有错误。
  • 嗯....我会添加我的版本,也许那里有问题。还有实际使用的http
  • 这也可能是 Linux 与 Mac 的区别 - 回溯看起来像您在 Mac 上运行,而我在 Linux 上。

标签: python python-asyncio aiohttp


【解决方案1】:

我知道这并不能直接回答您的问题,但实际上在 aiohttp request life-cycle 中有一些异步调用,所以您必须在几个地方使用 await

import asyncio

import aiohttp

URL = "https://stackoverflow.com"


async def main():
    session = aiohttp.ClientSession()
    resp = await session.get(URL)
    html = await resp.text()

    print(f"{URL} <{resp.status}> ({len(html)})")

    resp.release()

    await session.close()


if __name__ == "__main__":
    asyncio.run(main())

通常且更简单的方法是使用context managers,这将确保正确关闭所有剩余资源:

import asyncio

import aiohttp

URLS = [
    "https://serverfault.com",
    "https://stackoverflow.com",
]


async def fetch(session, url):
    async with session.get(url) as resp:
        html = await resp.text()

        print(f"{url} <{resp.status}>")

    return {url: len(html)}


async def main():
    tasks = []

    async with aiohttp.ClientSession() as session:
        for url in URLS:
            tasks.append(asyncio.create_task(fetch(session, url)))

        data = await asyncio.gather(*tasks)

    print(data)


if __name__ == "__main__":
    asyncio.run(main())

测试:

$ python test.py
https://serverfault.com <200>
https://stackoverflow.com <200>
[{'https://serverfault.com': 143272}, {'https://stackoverflow.com': 191046}]

【讨论】:

    【解决方案2】:

    这里可能会发生两件事:

    1. 你没有await正在做你应该做的事情
    2. 您调用的 URL 是错误请求,事件循环在您有机会了解实际情况之前就出错了。

    根据aiohttp documentation

    默认情况下,aiohttp 对 HTTPS 协议使用严格检查。可以通过将 ssl 设置为 False 来放松认证检查

    因此,您使用的urls 很可能达到了此阈值,您将被踢出局。换行:

    tasks = [session.get(url) for url in urls]
    

    tasks = [session.get(url, ssl=False) for url in urls]
    

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 2018-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多