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

时间:2017-08-07 21:09:53

标签: python multithreading python-3.x python-asyncio

我试图编写一个不和谐机器人,用来通过http休息呼叫获取数据来更新用户。

由于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和异步函数都很陌生。

2 个答案:

答案 0 :(得分:1)

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

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

-

my_background_task

答案 1 :(得分:0)

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

我不确定这是不是我应该这样做的方式,但这就是让我脱离泡菜的原因。