如何在asycio后台线程中使用aiohttp
问题描述:
我正在尝试编写一个不和谐的机器人程序,它使用我从http休息调用中获取的数据更新用户。如何在asycio后台线程中使用aiohttp
由于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")
它使用同步“请求”库足够简单。但是,我可以运行这个过程几个小时,直到它崩溃。我假设因为'请求'未能完成无限循环。
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
,它会自动选择当前事件循环,所以你应该叫 - 的
fetch
功能不应该await resp
。resp
那里不是一个协程。你可能想return await resp.json()
(并删除my_background_task
额外.json()
) - 在
my_method
,你已经在协程运行,由async def
所示。所以要调用另一个协程,你应该是await
-ing它,而不是创建一个新的事件循环,并在新的循环中运行它。 - 在
my_background_task
中,您正在等待一些毫无意义的事情:检查运算符的优先级await,您在协程上调用.__getitem__
,然后等待__getitem__
的结果,这与您想要的结果相反。 - 仍然在该行上,响应关闭后,您无法尝试读取响应的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"]