2015-01-06 4 views
32

ich den folgenden Code haben:Wenn asyncio verwenden, wie können Sie alle laufenden Aufgaben vor beenden die Ereignisschleife Abschalten

@asyncio.coroutine 
def do_something_periodically(): 
    while True: 
     asyncio.async(my_expensive_operation()) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

ich diese Funktion bis zur vollständigen laufen. Das Problem tritt auf, wenn Herunterfahren festgelegt ist - die Funktion wird beendet und alle ausstehenden Aufgaben werden nie ausgeführt. (Sie sehen dies als Fehler

task: <Task pending coro=<report() running at script.py:33> wait_for=<Future pending cb=[Task._wakeup()]>> 

). Wie plane ich ein Herunterfahren korrekt?

Um einen Kontext zu geben, schreibe ich einen Systemmonitor, der alle 5 Sekunden aus/proc/stat liest, die CPU-Nutzung in diesem Zeitraum berechnet und dann das Ergebnis an einen Server sendet. Ich möchte diese Überwachungsjobs so lange planen, bis ich signerm erhalte, wenn ich mit der Planung aufhöre, auf den Abschluss aller aktuellen Jobs warte und elegant aus dem System auschecke.

+0

etwas Kontext zu geben, ich bin ein System-Monitor zu schreiben, die von/proc/stat liest alle 5 Sekunden , berechnet die CPU-Nutzung in diesem Zeitraum und sendet das Ergebnis dann an ein se rver. Ich möchte diese Überwachungsjobs so lange planen, bis ich signerm erhalte, wenn ich mit der Planung aufhöre, auf den Abschluss aller aktuellen Jobs warte und elegant aus dem System auschecke. – derekdreery

+0

haben Sie versucht, yield von my_expensive_operation() \ n yield von asyncio.sleep (my_interval - timer()% my_interval) 'stattdessen? – jfs

+0

Ich könnte nur lange genug schlafen, dass ich weiß, dass alles fertig ist, aber das scheint nicht sehr sauber zu sein. Ich habe mich gefragt, ob es eine Möglichkeit gibt, Aufgaben zu planen und dann die Schleife auszuführen, bis alle geplanten Aufgaben abgeschlossen sind. Wenn in javascript (node.js) das Hauptprogramm das Ende erreicht, aber Callbacks gesetzt sind, wird der Prozess ausgeführt, bis alle Callbacks entfernt sind. – derekdreery

Antwort

33

Sie können nicht abgeschlossene Aufgaben abrufen und die Schleife erneut ausführen, bis sie beendet sind, dann die Schleife schließen oder Ihr Programm beenden.

pending = asyncio.Task.all_tasks() 
loop.run_until_complete(asyncio.gather(*pending)) 
  • anhängig ist eine Liste der anstehenden Aufgaben.
  • asyncio.gather() erlaubt, auf mehrere Aufgaben gleichzeitig zu warten.

Wenn Sie alle Aufgaben, um sicherzustellen, dass in einem Koroutine (vielleicht haben Sie eine „Haupt“ Koroutine haben) abgeschlossen ist, können Sie es auf diese Weise tun, zum Beispiel:

@asyncio.coroutine 
def do_something_periodically(): 
    while True: 
     asyncio.async(my_expensive_operation()) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

    yield from asyncio.gather(*asyncio.Task.all_tasks()) 

Auch in dieser Fall, da alle Aufgaben in der gleichen Koroutine erstellt werden, haben Sie bereits Zugriff auf die Aufgaben:

@asyncio.coroutine 
def do_something_periodically(): 
    tasks = [] 
    while True: 
     tasks.append(asyncio.async(my_expensive_operation())) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

    yield from asyncio.gather(*tasks) 
+1

Sehr hilfreich! Nur eine Anmerkung zur zweiten Methode: Ich denke *, dass jede Aufgabe, die Sie an die Liste anhängen, einen offenen Dateideskriptor darstellt - das bedeutet, dass Sie unter (sagen wir) Linux Ihr Dateilimit ('ulimit -n') vorher treffen konnten Die Coroutine ist beendet. – detly

+0

Hallo, Was meinst du mit "repräsentiert"? AFAIK, Aufgaben öffnen keine Dateiobjekte. –

+0

Ich habe mit der zweiten Methode festgestellt, dass ich Fehlermeldungen über zu viele offene Dateideskriptoren bekomme. Ich denke *, dass jede Aufgabe einen Dateideskriptor benötigt, um zu funktionieren. Beachten Sie, dass ein "Dateideskriptor" nicht dasselbe ist wie eine geöffnete Datei, sie können auch diejenigen sein, die vom ['select()'] verwendet werden (http://www.gnu.org/software/libc/manual/ html_node/Warten auf I_002fO.html # index-file-descriptor-sets_002c-for-select) Aufruf (was ich glaube, die 'asyncio'-Bibliothek verwendet). Wenn Sie also ein Benutzerlimit von ein paar tausend offenen Dateideskriptoren und viele weitere Tasks haben, können Probleme auftreten. – detly

Verwandte Themen