asyncio.run() 不能从正在运行的事件循环中调用

我想使用 asyncio 来获取网页 html。


我在 jupyter notebook 中运行以下代码:


import aiofiles

import aiohttp

from aiohttp import ClientSession


async def get_info(url, session):

    resp = await session.request(method="GET", url=url)

    resp.raise_for_status()

    html = await resp.text(encoding='GB18030')

    with open('test_asyncio.html', 'w', encoding='utf-8-sig') as f:

        f.write(html)

    return html

    

async def main(urls):

    async with ClientSession() as session:

        tasks = [get_info(url, session) for url in urls]

        return await asyncio.gather(*tasks)


if __name__ == "__main__":

    url = ['http://huanyuntianxiazh.fang.com/house/1010123799/housedetail.htm', 'http://zhaoshangyonghefu010.fang.com/house/1010126863/housedetail.htm']

    result = asyncio.run(main(url))

然而,它返回 RuntimeError: asyncio.run() cannot be called from a running event loop


问题是什么?


如何解决?


慕婉清6462132
浏览 1171回答 2
2回答

拉莫斯之舞

该asyncio.run()文件说:当另一个异步事件循环在同一线程中运行时,无法调用此函数。在您的情况下,jupyter(IPython ≥ 7.0)已经在运行事件循环:您现在可以在 IPython 终端和笔记本中的顶层使用 async/await,它应该——在大多数情况下——“正常工作”。将 IPython 更新到版本 7+,将 IPykernel 更新到版本 5+,然后您就可以参加比赛了。因此,您无需自己启动事件循环,而是可以await main(url)直接调用,即使您的代码位于任何异步函数之外。Jupyter/IPythonasync def main():    print(1)    await main()蟒蛇 (≥ 3.7)import asyncioasync def main():    print(1)    asyncio.run(main())在您的代码中,将给出:url = ['url1', 'url2']result = await main(url)for text in result:    pass # text contains your html (text) response警告与 IPython 相比,Jupyter 使用循环的方式略有不同。

跃然一笑

要添加 tocglacet的答案 - 如果想要检测循环是否正在运行并自动调整(即main()在现有循环上运行,否则asyncio.run()),这里是一个可能有用的片段:# async def main():#&nbsp; &nbsp; &nbsp;...try:&nbsp; &nbsp; loop = asyncio.get_running_loop()except RuntimeError:&nbsp; # 'RuntimeError: There is no current event loop...'&nbsp; &nbsp; loop = Noneif loop and loop.is_running():&nbsp; &nbsp; print('Async event loop already running. Adding coroutine to the event loop.')&nbsp; &nbsp; tsk = loop.create_task(main())&nbsp; &nbsp; # ^-- https://docs.python.org/3/library/asyncio-task.html#task-object&nbsp; &nbsp; # Optionally, a callback function can be executed when the coroutine completes&nbsp; &nbsp; tsk.add_done_callback(&nbsp; &nbsp; &nbsp; &nbsp; lambda t: print(f'Task done with result={t.result()}&nbsp; << return val of main()'))else:&nbsp; &nbsp; print('Starting new event loop')&nbsp; &nbsp; asyncio.run(main())
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python