如何在 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 resp
。 resp
不是协程。您可能想要 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"]
我正在尝试编写一个 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 resp
。resp
不是协程。您可能想要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"]