Pracuję nad skryptem Pythona, który uruchamia kilka procesów i połączeń z bazą danych. Co jakiś czas chcę zabijać skrypt sygnałem Ctrl+ Ci chciałbym zrobić porządki.
W Perlu zrobiłbym to:
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
print "Caught ^C \n";
exit (0);
}
Jak zrobić analogię tego w Pythonie?
./program.py > output.log
. Kiedy naciskasz Ctrl-C , chcesz, aby Twój program z wdziękiem zakończył działanie, rejestrując, że wszystkie pliki danych zostały opróżnione i oznaczone jako czyste, aby potwierdzić, że pozostały w znanym dobrym stanie. Ale Ctrl-C wysyła SIGINT do wszystkich procesów w potoku, więc powłoka może zamknąć STDOUT (teraz „output.log”), zanim program.py zakończy drukowanie ostatniego dziennika. Python narzeka: „zamknięcie nie powiodło się w niszczeniu obiektu pliku: Błąd w sys.excepthook:”.Możesz traktować to jak wyjątek (KeyboardInterrupt), jak każdy inny. Utwórz nowy plik i uruchom go ze swojej powłoki z następującą zawartością, aby zobaczyć, co mam na myśli:
źródło
signal.signal(signal.SIGINT, signal.default_int_handler)
albo zawiedziesz się, ponieważ KeyboardInterrupt nie uruchamia się w każdej sytuacji, w której powinien zadziałać! Szczegóły są tutaj .I jako menedżer kontekstu:
Używać:
Zagnieżdżone procedury obsługi:
Stąd: https://gist.github.com/2907502
źródło
StopIteration
aby przerwać najbardziej wewnętrzną pętlę po naciśnięciu Ctrl-C, prawda?Możesz obsłużyć CTRL+ C, wychwytując
KeyboardInterrupt
wyjątek. Możesz zaimplementować dowolny kod czyszczenia w module obsługi wyjątków.źródło
Z dokumentacji Pythona :
źródło
Jeszcze inny urywek
O których mowa
main
w funkcji głównej iexit_gracefully
jako CTRL+ cobsługiźródło
Dostosowałem kod z @udi do obsługi wielu sygnałów (nic szczególnego):
Ten kod obsługuje wywołanie przerwania klawiatury (
SIGINT
) iSIGTERM
(kill <process>
)źródło
W przeciwieństwie do jego odpowiedzi Matta J używam prostego przedmiotu. Daje mi to możliwość parsowania tego modułu obsługi do wszystkich wątków, które muszą zostać zatrzymane.
Gdzie indziej
źródło
time.sleep()
zamiast robić zajętą pętlę na zmiennej.Możesz użyć funkcji we wbudowanym module sygnałowym Pythona, aby skonfigurować procedury obsługi sygnałów w Pythonie. W szczególności
signal.signal(signalnum, handler)
funkcja służy do zarejestrowaniahandler
funkcji dla sygnałusignalnum
.źródło
dziękuję za istniejące odpowiedzi, ale dodane
signal.getsignal()
źródło
Jeśli chcesz mieć pewność, że proces czyszczenia dobiegnie końca, dodam odpowiedź Matt'a J, używając SIG_IGN , aby dalsze
SIGINT
ignorowanie zapobiegało przerwaniu czyszczenia.źródło
Osobiście nie mogłem użyć try / oprócz KeyboardInterrupt, ponieważ korzystałem z trybu standardowego gniazda (IPC), który blokuje. Tak więc SIGINT został wskazany, ale pojawił się dopiero po otrzymaniu danych na gnieździe.
Ustawienie procedury obsługi sygnału zachowuje się tak samo.
Z drugiej strony działa to tylko dla faktycznego terminala. Inne środowiska początkowe mogą nie akceptować Ctrl+ Club wstępnie obsługiwać sygnał.
Ponadto w Pythonie istnieją „wyjątki” i „wyjątki podstawowe”, które różnią się tym, że interpreter musi sam wyjść bezproblemowo, więc niektóre wyjątki mają wyższy priorytet niż inne (wyjątki pochodzą od wyjątku BaseException)
źródło