【问题标题】:how to use aiohttp in an asycio background thread如何在异步后台线程中使用 aiohttp
【发布时间】:2017-08-09 20:48:22
【问题描述】:

我正在尝试编写一个不和谐的机器人,用我从 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")

使用同步“请求”库就足够简单了。但是我可以运行它大约几个小时,直到它崩溃。我假设是因为“请求”未能完成无限循环。

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

【问题讨论】:

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


    【解决方案1】:

    如果没有从您的 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__,然后等待__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"]
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多