如何在 asycio 后台线程中使用 aiohttp

how to use aiohttp in an asycio background thread

我正在尝试编写一个 discord 机器人,用我从 http rest 调用中获取的数据更新用户。

由于 discord.py 使用 asyncio,我想我会尝试遵循这种方法。

async def my_background_task():

    print("starting BG task")
    await client.wait_until_ready()
    while not client.is_closed:
        requests.get(getMyUrl()).json()["dict_element"]
        #do more stuff

client.loop.create_task(my_background_task())
client.run("api key goes here")

使用同步 "request" 库非常简单。但是,我可以 运行 这大约几个小时,直到它崩溃。我假设是因为 'request' 未能完成无限循环。

async def fetch(session, url):
    async with session.get(url) as resp:
        print(resp.status)
        return await resp

async def fetch_url(loop, url):
    async with aiohttp.ClientSession(loop=loop) as session:
        await fetch(session, url)

async def my_method(url):

    loop = asyncio.get_event_loop()
    return loop.run_until_complete(fetch_url(loop,url))

async def my_background_task():

    print("starting BG task")
    await client.wait_until_ready()
    while not client.is_closed:
        await my_method.("www.theinternet.com/restcall").json()["dict_element"]
        #do more stuff

所以我现在尝试使用 aiohttp,但 运行 遇到此循环中异步循环的问题。

我还没有找到关于如何处理这个问题的正确解释。我对 python 和异步函数还很陌生。

我通过另一个后台任务解决了这个问题,该任务将 http 响应保存为全局变量并自行更新。

我不确定这是否是我应该做的,但这就是让我摆脱困境的原因。

如果没有您从 aiohttp 版本中得到的错误,很难猜到。但乍一看,我会说:

  • 无需将事件循环显式传递给ClientSession,它会自动选择当前事件循环,因此您只需调用ClientSession()
  • fetch 函数不应该 await respresp 不是协程。您可能想要 return await resp.json()(并删除 my_background_task 中多余的 .json()
  • my_method 中,您已经 运行 在协程中,如 async def 所示。所以要调用另一个协程,你应该 await-ing 它,而不是创建一个新的事件循环和 运行 它在那个新循环中。
  • my_background_task 中,您正在等待一些没有任何意义的事情:检查 await 的运算符优先级,您在协程上调用 .__getitem__,然后等待 [= 的结果24=],这与你想要的相反。
  • 并且仍然在该行,您不能在响应关闭后尝试读取响应的 json 正文(一旦您退出 async with,响应就会关闭,即一旦 fetch 方法完成。
  • 最后,您不应该在每个循环中都重新创建 ClientSession。它存在以便可以在请求之间共享,因此您应该在 my_background_task 中创建一次并使用它

-

async def fetch(session, url):
    async with session.get(url) as resp:
        print(resp.status)
        return await resp.json()

async def my_background_task()
    print("starting BG task")
    await client.wait_until_ready()
    async with aiohttp.ClientSession() as session:
        while not client.is_closed:
            data = await fetch(session, "www.theinternet.com/restcall")
            element = data["dict_element"]