20

I'm trying to make a bunch of requests (~1000) using Asyncio and the aiohttp library, but I am running into a problem that I can't find much info on.

When I run this code with 10 urls, it runs just fine. When I run it with 100+ urls, it breaks and gives me RuntimeError: Event loop is closed error.

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()

The stack trace can be found here.

Any help or insight would be greatly appreciated as I've been banging my head over this for a few hours now. Obviously this would suggest that an event loop has been closed that should still be open, but I don't see how that is possible.

4

2 回答 2

18

该错误被归档为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()
于 2015-09-16T17:43:03.237 回答
7

没错,loop.getaddrinfo使用 a在线程ThreadPoolExecutor中运行socket.getaddrinfo

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

于 2015-09-16T14:26:32.070 回答