Asyncio RuntimeError:事件循环已关闭

新手上路,请多包涵

我正在尝试使用 Asyncio 和 aiohttp 库发出一堆请求(~1000),但我遇到了一个我找不到太多信息的问题。

当我用 10 个 url 运行这段代码时,它运行得很好。当我使用 100 多个 url 运行它时,它会中断并给我 RuntimeError: Event loop is closed 错误。

 import asyncio
import aiohttp

@asyncio.coroutine
def get_status(url):
    code = '000'
    try:
        res = yield from asyncio.wait_for(aiohttp.request('GET', url), 4)
        code = res.status
        res.close()
    except Exception as e:
        print(e)
    print(code)

if __name__ == "__main__":
    urls = ['https://google.com/'] * 100
    coros = [asyncio.Task(get_status(url)) for url in urls]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(coros))
    loop.close()

可以在 此处 找到堆栈跟踪。

任何帮助或见解将不胜感激,因为我已经为此苦苦思索了几个小时。显然,这表明事件循环已关闭但仍应打开,但我不明白这是怎么可能的。

原文由 Patrick Allen 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 861
2 个回答

没错, loop.getaddrinfo 使用 ThreadPoolExecutor socket.getaddrinfo

您正在使用带有超时的 asyncio.wait_for ,这意味着 res = yield from asyncio.wait_for... 将在 4 秒后引发 asyncio.TimeoutError 。然后 get_status 协程返回 None 并且循环停止。如果作业在此之后完成,它将尝试在事件循环中安排回调并引发异常,因为它已经关闭。

原文由 Vincent 发布,翻译遵循 CC BY-SA 3.0 许可协议

该错误被归档为 https://github.com/python/asyncio/issues/258 敬请期待。

作为快速解决方法,我建议使用自定义执行程序,例如

loop = asyncio.get_event_loop()
executor = concurrent.futures.ThreadPoolExecutor(5)
loop.set_default_executor(executor)

在完成你的程序之前,请做

executor.shutdown(wait=True)
loop.close()

原文由 Andrew Svetlov 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题