2015-01-06 16 views
32

Mam następujący kod:Podczas korzystania asyncio, jak można pozwolić wszystkie zadania uruchomione, aby zakończyć przed zamknięciem pętli zdarzeń

@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 

uruchomić tę funkcję aż do zakończenia. Problem występuje, gdy jest ustawione wyłączanie - funkcja zostaje zakończona, a wszelkie oczekujące zadania nigdy nie są uruchamiane. (Widać to jako błąd:

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

). Jak poprawnie zaplanować zamknięcie?

Aby podać pewien kontekst, piszę monitor systemu, który odczytuje z/proc/stat co 5 sekund, oblicza użycie procesora w tym okresie, a następnie wysyła wynik do serwera. Chcę kontynuować planowanie tych zadań monitorowania, dopóki nie otrzymam sigterm, gdy zatrzymam planowanie, poczekam na zakończenie wszystkich bieżących zadań i zakończę wdzięcznie.

+0

dać pewien kontekst, Piszę monitor systemu, który odczytuje z pliku/proc/stat co 5 sekund , oblicza użycie procesora w tym okresie, a następnie wysyła wynik do se rver. Chcę kontynuować planowanie tych zadań monitorowania, dopóki nie otrzymam sigterm, gdy zatrzymam planowanie, poczekam na zakończenie wszystkich bieżących zadań i zakończę wdzięcznie. – derekdreery

+0

próbowałeś 'yield z my_expensive_operation() \ n wydaj z' asyncio.sleep (my_interval - timer()% my_interval) 'zamiast? – jfs

+0

Mogłem po prostu spać na tyle długo, że wiem, że wszystko się skończyło, ale to nie wydaje się bardzo czyste. Zastanawiam się, czy istnieje sposób zaplanowania zadań, a następnie uruchom pętlę, dopóki wszystkie zaplanowane zadania nie zostaną zakończone. W javascript (node.js), jeśli główny program osiąga koniec, ale są ustawione wywołania zwrotne, proces jest uruchamiany do momentu usunięcia wszystkich wywołań zwrotnych. – derekdreery

Odpowiedz

33

Możesz odzyskać niedokończone zadania i ponownie uruchomić pętlę, aż do zakończenia, a następnie zamknąć pętlę lub zamknąć program.

pending = asyncio.Task.all_tasks() 
loop.run_until_complete(asyncio.gather(*pending)) 
  • oczekiwaniu znajduje się lista oczekujących zadań.
  • asyncio.gather() pozwala czekać na kilka zadań jednocześnie.

Jeśli chcesz, aby wszystkie zadania są wykonywane wewnątrz współprogram (może masz „main” współprogram), można zrobić to w ten sposób, na przykład:

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

Również w tym przypadku, ponieważ wszystkie zadania są tworzone w tym samym współprogram, masz już dostęp do zadań:

@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

Bardzo pomocny! Wystarczy napisać o drugiej metodzie: * myślę, * że każde zadanie dodane do listy reprezentuje otwarty deskryptor pliku - oznacza to, że na (powiedzmy) Linuksie możesz trafić swój otwarty limit plików ('ulimit -n') przed coroutine jest skończony. – detly

+0

Witam, Co masz na myśli przez "reprezentuje"? AFAIK, zadania nie otwierają obiektów plików. –

+0

Znalazłem, używając drugiej metody, że dostaję komunikaty o błędach o zbyt wielu otwartych deskryptorów plików. * Myślę, że * każde zadanie wymaga działania deskryptora pliku. Zauważ, że "deskryptor pliku" to nie to samo co otwarty plik, mogą to być również te używane przez ['select()'] (http://www.gnu.org/software/libc/manual/ html_node/Waiting-for-I_002fO.html # index-file-descriptor-sets_002c-for-select) wywołanie (które, jak sądzę, używa biblioteka 'asyncio'). Więc jeśli masz limit kilku tysięcy otwartych deskryptorów plików i wiele więcej zadań, możesz napotkać problemy. – detly

Powiązane problemy