Chcę wielokrotnie wykonywać funkcję w Pythonie co 60 sekund na zawsze (tak jak NSTimer w Celu C). Ten kod będzie działał jako demon i faktycznie przypomina wywoływanie skryptu python co minutę przy użyciu crona, ale bez konieczności konfigurowania go przez użytkownika.
W tym pytaniu dotyczącym crona zaimplementowanego w Pythonie rozwiązanie wydaje się efektywnie po prostu sleep () przez x sekund. Nie potrzebuję tak zaawansowanych funkcji, więc być może coś takiego zadziałałoby
while True:
# Code executed here
time.sleep(60)
Czy są jakieś przewidywalne problemy z tym kodem?
time.sleep(60)
mogą również powrócić zarówno wcześniej, jak i późniejOdpowiedzi:
Jeśli twój program nie ma jeszcze pętli zdarzeń, użyj modułu harmonogramu , który implementuje harmonogram zdarzeń ogólnego przeznaczenia.
Jeśli już przy użyciu biblioteki pętli wydarzenie jak
asyncio
,trio
,tkinter
,PyQt5
,gobject
,kivy
, i wiele innych - po prostu zaplanować zadanie przy użyciu metod istniejącą bibliotekę pętli zdarzeń, w zamian.źródło
enterabs()
aby tego uniknąć. Oto wersja bez driftu dla porównania .time.sleep
mogą się tutaj gromadzić. „wykonaj co X sekund” i „wykonaj z opóźnieniem ~ X sekund wielokrotnie” nie są takie same. Zobacz także ten komentarzZablokuj pętlę czasu na zegarze systemowym w następujący sposób:
źródło
twisted
odpowiedź to jedyne odpowiedzi, które uruchamiają funkcję cox
sekundę. Reszta wykonuje funkcję z opóźnieniemx
kilku sekund po każdym wywołaniu.from time import time, sleep
ze względu na implikacje egzystencjalne;)starttime
jeśli zaczniesz od zsynchronizowania go z określonym czasem:time.sleep(60 - time.time() % 60)
działało dobrze dla mnie. Użyłem go jakotime.sleep(1200 - time.time() % 1200)
i daje mi logi:00 :20 :40
, dokładnie tak, jak chciałem.sleep()
,timer()
precyzja i jak długo to trwa do wykonania ciała pętli, ale średnio iteracji zawsze występują na granicach przedziału (nawet jeśli niektóre z nich są pomijane)while keep_doing_it(): sleep(interval - timer() % interval)
. Porównaj to z tym,while keep_doing_it(): sleep(interval)
gdzie błędy mogą się kumulować po kilku iteracjach.Warto rozważyć Twisted, która jest biblioteką sieciową Pythona, która implementuje wzorzec Reactor .
Podczas gdy „while True: sleep (60)” prawdopodobnie będzie działać Twisted prawdopodobnie już implementuje wiele funkcji, które w końcu będą potrzebne (demonizacja, rejestrowanie lub obsługa wyjątków, jak wskazał bobince) i prawdopodobnie będzie to bardziej niezawodne rozwiązanie
źródło
Jeśli chcesz mieć nieblokujący sposób okresowego wykonywania swojej funkcji, zamiast blokującej nieskończonej pętli użyłbym wątkowego timera. W ten sposób Twój kod może działać i wykonywać inne zadania, a twoja funkcja może być wywoływana co n sekund. Często używam tej techniki do drukowania informacji o postępach w przypadku długich zadań intensywnie wykorzystujących procesor / dysk / sieć.
Oto kod, który opublikowałem w podobnym pytaniu, z kontrolą start () i stop ():
Stosowanie:
Cechy:
start()
istop()
można bezpiecznie dzwonić wiele razy, nawet jeśli stoper już się uruchomił / zatrzymałinterval
dowolnym momencie, zacznie obowiązywać po następnym uruchomieniu. To samo dotyczyargs
,kwargs
a nawetfunction
!źródło
def _run(self)
Próbuję owinąć głowę wokół dlaczego nazywaszself.start()
wcześniejself.function()
. Czy możesz rozwinąć? Wydaje mi się, że dzwonienie jakostart()
pierwszeself.is_running
zawszeFalse
tak będzie, a potem zawsze będziemy rozwijać nowy wątek.x
sekundę (tj. T = 0, t = 1x, t = 2x, t = 3x, ...), gdzie na oryginalnych plakatach przykładowy kod uruchamia funkcję z przerwą x sekundową pomiędzy nimi. Ponadto, jak sądzę, w tym rozwiązaniu występuje błąd, któryinterval
jest krótszy niż czas potrzebnyfunction
do wykonania. W takim przypadkuself._timer
zostanie nadpisany wstart
funkcji..function()
after.start()
ma uruchomić funkcję przy t = 0. I nie sądzę, że będzie to problem, jeślifunction
zajmie to więcej czasuinterval
, ale tak, mogą być pewne warunki wyścigowe w kodzie.Uważam, że łatwiejszym sposobem jest:
W ten sposób Twój kod jest wykonywany, a następnie czeka 60 sekund, a następnie wykonuje ponownie, czeka, wykonuje itp. Nie musisz komplikować rzeczy: D
źródło
time.sleep()
uruchomić coś co X sekundtime.sleep()
wwhile True
pętli, jak:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Jeśli chcesz to zrobić bez blokowania pozostałego kodu, możesz użyć tego, aby uruchomić go we własnym wątku:
To rozwiązanie łączy w sobie kilka funkcji rzadko spotykanych w innych rozwiązaniach:
threading.Timer
lub czymkolwiek innym ), spowoduje to przerwanie łańcucha. Wówczas nie będą wykonywane dalsze egzekucje, nawet jeśli przyczyna problemu została już naprawiona. Prosta pętla i czekanie z prostąsleep()
jest znacznie bardziej niezawodne w porównaniu.next_time += delay
zamiast.źródło
Oto aktualizacja kodu MestreLion, która pozwala uniknąć dryfowania w czasie.
Klasa RepeatedTimer wywołuje tutaj daną funkcję co „interwał” sekund, zgodnie z żądaniem OP; harmonogram nie zależy od czasu wykonywania funkcji. Podoba mi się to rozwiązanie, ponieważ nie ma zależności od biblioteki zewnętrznej; to jest po prostu czysty python.
Przykładowe użycie (skopiowane z odpowiedzi MestreLion):
źródło
Jakiś czas temu napotkałem podobny problem. Może http://cronus.readthedocs.org może pomóc?
W wersji 0.2 działa następujący fragment kodu
źródło
Główną różnicą między tym a cron jest to, że wyjątek na dobre zabije demona. Możesz owinąć się łapaczem wyjątków i rejestratorem.
źródło
Jedna możliwa odpowiedź:
źródło
Skończyło się na użyciu modułu harmonogramu . Interfejs API jest fajny.
źródło
Używam metody Tkinter after (), która nie „kradnie gry” (podobnie jak moduł harmonogramu , który został wcześniej zaprezentowany), tzn. Pozwala na równoległe działanie innych rzeczy:
do_something1()
ido_something2()
może działać równolegle i z dowolną prędkością interwału. Tutaj drugi zostanie wykonany dwa razy szybciej. Zauważ też, że użyłem prostego licznika jako warunku do zakończenia którejkolwiek z funkcji. Możesz użyć dowolnej innej lub dowolnej opcji, jeśli chcesz, jaką funkcję uruchomić, dopóki program się nie zakończy (np. Zegar).źródło
after
nie pozwala na równoległe działanie. Tkinter jest jednowątkowy i może robić tylko jedną rzecz naraz. Jeśli coś zaplanowane przezafter
jest uruchomione, nie działa równolegle z resztą kodu. Jeśli obado_something1
ido_something2
są zaplanowane w tym samym czasie, będą uruchamiane sekwencyjnie, a nie równolegle.sched
, a to będzie działać dokładnie tak samo jak twoje.Oto dostosowana wersja do kodu z MestreLion. Oprócz oryginalnej funkcji ten kod:
1) dodaj pierwszy_interwał używany do uruchomienia timera w określonym czasie (osoba dzwoniąca musi obliczyć pierwszy_interwał i przekazać)
2) rozwiązać warunek wyścigu w oryginalnym kodzie. W oryginalnym kodzie, jeśli wątek kontrolny nie anulował uruchomionego timera („Zatrzymaj timer i anuluj wykonanie akcji timera. Działa to tylko wtedy, gdy timer jest nadal w fazie oczekiwania.” Cytowany z https: // docs.python.org/2/library/threading.html ), licznik czasu będzie działał bez końca.
źródło
Wydaje się to o wiele prostsze niż przyjęte rozwiązanie - czy ma wady, których nie rozważam? Przybyłem tutaj, szukając makaronu, który byłby bardzo prosty i był rozczarowany.
Który wyprowadza asynchronicznie.
Ma dryf w tym sensie, że jeśli uruchamiane zadanie zajmuje znaczną ilość czasu, wówczas interwał wynosi 2 sekundy + czas zadania, więc jeśli potrzebujesz dokładnego planowania, nie jest to dla ciebie.
Uwaga:
daemon=True
flaga oznacza, że ten wątek nie zablokuje zamknięcia aplikacji. Na przykład wystąpił problempytest
polegający na tym, że zawieszał się w nieskończoność po uruchomieniu testów, czekając na zakończenie thead.źródło
Używam tego, aby powodować 60 zdarzeń na godzinę, przy czym większość zdarzeń występuje w tej samej liczbie sekund po całej minucie:
W zależności od rzeczywistych warunków możesz dostać kleszcze długości:
ale pod koniec 60 minut będziesz miał 60 tyknięć; i większość z nich pojawi się z prawidłowym przesunięciem w stosunku do minuty, którą preferujesz.
W moim systemie mam typowy dryf <1/20 sekundy, aż pojawi się potrzeba korekty.
Zaletą tej metody jest rozdzielczość dryftu zegara; co może powodować problemy, jeśli robisz takie rzeczy, jak dodawanie jednego elementu na tyknięcie i oczekujesz 60 elementów dodawanych na godzinę. Nieuwzględnienie dryftu może powodować wtórne wskazania, takie jak średnie ruchome, w celu uwzględnienia danych zbyt głęboko w przeszłości, co prowadzi do wadliwych wyników.
źródło
np. Wyświetl aktualny czas lokalny
źródło
źródło
Oto inne rozwiązanie bez użycia dodatkowych bibliotek.
źródło