Schlaufe die sich genau jede Sekunde wiederhohlt

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
hexa

Guten abend liebe Community

Ich habe vor ein paar Tagen angefangen Python zu lernen. Habe mir nun aus diesem Grund, folgende Übungsaufgabe gestellt: Ich versuche eine Schlaufe zu erstellen, die genau im 1 Sekunden takt wieder von vorne anfängt. Habe schon viel dazu gegoogelt und in diversen Büchern nachgeschaut. Leider hab ich nur Ansätze gefunden die immer mit einer Verzögerung von ein paar milisekunden funktionieren. Heisst, nach ein paar minuten war die angezeigte Zeit ein paar sekunden zu früh. Diese funktionierten hauptsächlich mit time.sleep und/oder mit threading.timer. Standet ihr schonmal vor diesem Problem? Wenn ja, habt ihr eine Lösung gefunden?

Ich erwarte natürlich kein fertiger Code nur etwas hilfe wie ich dieses Problem lösen könnte.

Grüsse
hexa
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Was du beschreibst läuft letztendlich auf ein Echtzeitsystem hinaus. Dafür gibt es keine einfache Lösung.

Gerade als Anfänger würde ich dir empfehlen, dich von dem Problem erstmal zu verabschieden.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Du meinst Schleife! So.

In freier Wildbahn habe ich so ein Problem, wie von dir erwogen, noch nicht gehabt. Ich will eigentlich immer, dass die Rechnungen möglichst schnell erledigt werden. Es gab das Problem schon mal und dazu auch Lösungen - ich habe es nicht getestet:

http://stackoverflow.com/questions/4745 ... -in-python
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

unter Linux würde man das Skript IMHO dann auch eher periodisch mit einer systemd Timer Unit oder einem cron-Job starten. Aber auch dann gibt's keine Garantie, dass das _genau_ nach 1s passiert.

Gruß, noisefloor
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Was spricht gegen das `sched`-Modul?
hexa

Vielen Dank für die schnellen Antworten :-)
Aus einem Beitrag deines Linke hab ich diese Möglichkeit gefunden:

Code: Alles auswählen

import time
starttime=time.time()
while True:
  print("tick")
  time.sleep(1.0 - ((time.time() - starttime) % 1.0))
funktioniert gut, soweit das Ausgeführte nicht länger als eine Sekunde überschreiten.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier nochmal ohne `sched`:

Code: Alles auswählen

from __future__ import print_function

from itertools import repeat
from time import sleep

try:
    from time import monotonic as timefunc
except ImportError:
    from time import time as timefunc

def repeated_call(func, delay, num_calls=None, check_interval=1e-4):
    for _ in  repeat(object(), num_calls):
        start = timefunc()
        while (timefunc() - start) < delay:
            sleep(check_interval)
        func()

def some_calculation():
    print('Got a result at', timefunc())

def main():
    repeated_call(some_calculation, delay=1, num_calls=20)

if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@snafu: Deine Funktion hat keinen Vorteil gegenüber einem einfachen `sleep`. Du zählst die Zeit, die `func` braucht nicht mit und Dein busy-Waiting ist auch nicht genauer als das was ein sleep-Aufruf auch könnte.

Hier noch eine Lösung per Iterator.

Code: Alles auswählen

from itertools import count
import time

def ticks(interval):
    start = time.time()
    for step in count(1):
        yield step
        seconds = start + step * interval - time.time()
        if seconds > 0:
            time.sleep(seconds)

for toc in ticks(1.0):
    print(toc)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Verbesserte Version:

Code: Alles auswählen

from __future__ import print_function

from time import sleep
from timeit import default_timer as timer

def repeated_call(func, num_calls, delay):
    for _ in range(num_calls):
        start = timer()
        func()
        remaining = start + delay - timer()
        if remaining > 0:
            sleep(remaining)

def some_calculation():
    sleep(0.5)
    print('Got a result at', timer())

def main():
    repeated_call(some_calculation, 20, 1)

if __name__ == '__main__':
    main()
Antworten