Asyncio RuntimeError: Event Loop is Closed

Estoy tratando de hacer un montón de solicitudes (~ 1000) usando Asyncio y la biblioteca aiohttp, pero tengo un problema en el que no puedo encontrar mucha información.

Cuando ejecuto este código con 10 urls, funciona bien. Cuando lo ejecuto con más de 100 urls, se rompe y me da RuntimeError: Event loop is closed error 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() 

La traza de stack se puede encontrar aquí .

Cualquier ayuda o idea sería muy apreciada, ya que me he estado golpeando la cabeza por esto durante algunas horas. Obviamente, esto sugeriría que se ha cerrado un bucle de eventos que aún debería estar abierto, pero no veo cómo es posible.

Tienes razón, loop.getaddrinfo usa un ThreadPoolExecutor para ejecutar socket.getaddrinfo en un hilo.

Estás usando asyncio.wait_for con un tiempo de espera, lo que significa que res = yield from asyncio.wait_for... generará un asyncio.TimeoutError después de 4 segundos. Luego, get_status coroutines devuelve None y el bucle se detiene. Si un trabajo finaliza después de eso, intentará progtwigr una callback en el bucle de eventos y genera una excepción ya que ya está cerrado.

El error se archiva como https://github.com/python/asyncio/issues/258 Manténgase sintonizado.

Como solución rápida, sugiero usar un ejecutor personalizado, por ejemplo,

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

Antes de terminar su progtwig por favor haga

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