Asyncio RuntimeError: Événement Boucle est bouclée
Je suis en train de faire un tas de demandes (~1000) à l'aide de Asyncio et la aiohttp de la bibliothèque, mais je suis confronté à un problème que je ne trouve pas beaucoup d'info sur.
Lorsque j'exécute ce code avec 10 url, il fonctionne très bien. Quand je le lance avec 100+ url, il se casse et me donne RuntimeError: Event loop is closed
erreur.
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 trace de la pile peut être trouvé ici.
Toute aide ou des connaissances serait grandement apprécié que j'ai été frapper ma tête sur ce pour quelques heures maintenant. Évidemment, cela suggère qu'une boucle d'événement a été fermé qui devrait encore être ouverte, mais je ne vois pas comment cela est possible.
- n'est pas
Asyncio
erreur. Python erreur récursive, limite atteinte. besoin de fil pour tous les non fonction de classe... - Tout d'abord, assurez-vous que vous utilisez la dernière aiohttp libération. Je suppose que vous faites. Techniquement aiohttp besoin d'une boucle d'itération après la fin de la demande de clôture des sous-jacents de sockets. Donc insérer
loop.run_until_complete(asyncio.sleep(0))
avantloop.close()
appel. - Votre traceback suggère qu'un travail soumis à un Exécuteur à run_in_executor retourné après que la boucle a été fermé. Bizarrement assez, aiohttp et asyncio ne pas utiliser
run_in_executor
... - merci pour la réponse, j'ai essayé de dormir avant de fermer, mais toujours pas de dés... d'autres idées?
- techniquement, ils n', la résolution DNS est effectuée par
run_in_executor
-- mais il devrait être fait avant la fin deget_status
tâches.
Vous devez vous connecter pour publier un commentaire.
Vous avez raison, de la boucle.getaddrinfo utilise un
ThreadPoolExecutor
pour exécutersocket.getaddrinfo
dans un thread.Vous utilisez asyncio.wait_for avec un délai d'attente, ce qui signifie
res = yield from asyncio.wait_for...
de soulever unasyncio.TimeoutError
après 4 secondes. Puis leget_status
coroutines retourNone
et la boucle s'arrête. Si une tâche se termine après que, il va essayer de programmer un rappel à la boucle d'événement et soulève une exception, puisqu'il est déjà fermé.loop._default_executor.shutdown(wait=True)
avant de fermer la boucle.socket.getaddrinfo
dans les 4 secondes qui me semble raisonnable, même si le nombre de travailleurs peut être augmenté. Vous pouvez également donner une coutumeTcpConnector
àrequest
afin de spécifier un délai d'attente de connexion:connector=aiohttp.TCPConnector(loop=loop, force_close=True, conn_timeout=1)
Le bug est déposé à titre de https://github.com/python/asyncio/issues/258
Restez à l'écoute.
Comme solution de rechange rapide je vous conseille d'utiliser exécuteur personnalisé, par exemple
Avant de terminer votre programme s'il vous plaît ne
Changed in version 3.5.3: BaseEventLoop.run_in_executor() no longer configures the max_workers of the thread pool executor it creates