2015-09-16 10 views
11

Ich versuche, eine Reihe von Anfragen (~ 1000) mit Asyncio und der aiohttp-Bibliothek zu machen, aber ich stoße auf ein Problem, dass ich nicht viele Informationen finden kann.Asyncio RuntimeError: Ereignisschleife ist geschlossen

Wenn ich diesen Code mit 10 URLs ausführen, läuft es gut. Wenn ich es mit 100+ URLs starte, bricht es und gibt mir RuntimeError: Event loop is closed Fehler.

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

Der Stack-Trace kann here finden.

Jede Hilfe oder Einsicht würde sehr geschätzt werden, da ich seit ein paar Stunden meinen Kopf darüber hämmere. Offensichtlich würde dies bedeuten, dass eine Ereignisschleife geschlossen wurde, die noch offen sein sollte, aber ich sehe nicht, wie das möglich ist.

+0

ist nicht 'Asyncio' Fehler

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

Bevor Sie Ihr Programm beenden. Python rekursiver Fehler, Limit erreicht. Need-Thread für alle Nicht-Klasse-Funktion ... – dsgdfg

+0

Stellen Sie zuerst sicher, dass Sie die neueste aiohttp-Version verwenden. Ich nehme an, Sie tun. Technisch aiohttp benötigt eine Schleife Iteration nach Abschluss der Anfrage zum Schließen zugrunde liegenden Sockets. Fügen Sie 'loop.run_until_complete (asyncio.sleep (0))' vor 'loop.close()' ein. –

+0

Ihr Traceback schlägt vor, dass ein Job an einen [Executor] (https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor) über [run_in_executor] (https: // docs .python.org/3/library/asyncio-eventloop.html # asyncio.BaseEventLoop.run_in_executor) zurückgegeben, nachdem die Schleife geschlossen wurde. Seltsamerweise [aiohttp] (https://github.com/KeepSafe/aiohttp/search?utf8=%E2%9C%93&q=run_in_executor&type=Code) und [asyncio] (https://github.com/python/asyncio/Suche? utf8 =% E2% 9C% 93 & q = run_in_executor) nicht 'run_in_executor' verwenden ... – Vincent

Antwort

3

Sie haben recht, loop.getaddrinfo verwendet ThreadPoolExecutor, um in einem Thread auszuführen.

Sie verwenden asyncio.wait_for mit einem Timeout, das res = yield from asyncio.wait_for... bedeutet, dass eine asyncio.TimeoutError nach 4 Sekunden erhöhen. Dann geben die get_status Korotinen None zurück und die Schleife stoppt. Wenn danach ein Job beendet wird, wird versucht, einen Rückruf in der Ereignisschleife einzuplanen und löst eine Ausnahme aus, da sie bereits geschlossen ist.

+0

Ahh, das ist sinnvoll, aber das ist die einzige Möglichkeit, um Request Timeouts zu implementieren. Weißt du, dass ich eine Auszeit nehmen kann, ohne die Schleife zu schließen? –

+0

@PatrickAllen Sie können die [Anzahl der Arbeiter] (https://github.com/python/asyncio/blob/27f3499f968e8734fef91677eb339b5d32a6f675/asyncio/base_events.py#L44), die standardmäßig 5 ist, erhöhen. – Vincent

+2

@PatrickAllen Oder verwenden Sie 'loop._default_executor.shutdown (wait = True)' 'vor dem Schließen der Schleife. – Vincent

16

Der Fehler ist abgelegt als https://github.com/python/asyncio/issues/258 Bleiben Sie dran.

Als schnelle Problemumgehung empfehle ich benutzerdefinierte Executor, z. bitte tun

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

Awesome Andrew, danke für deine Hilfe. Ich wusste nicht, dass ich mit einem Teil des Teams sprach :). Danach auf GH –

+0

'Geändert in Version 3.5.3: BaseEventLoop.run_in_executor() konfiguriert nicht mehr die max_workers des Thread-Pool-Executor erstellt – RomanPerekhrest

+0

Andrew, können Sie nicht" schnelle Abhilfe "aber einige robuste Workaround für Python 3.5 vorschlagen? – RomanPerekhrest

Verwandte Themen