Seite 1 von 1

Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 21:09
von 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

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 21:31
von DasIch
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.

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 21:35
von pixewakb
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

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 21:55
von noisefloor
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

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 22:01
von snafu
Was spricht gegen das `sched`-Modul?

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 22:39
von 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.

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 22:57
von snafu
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()

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Dienstag 29. November 2016, 23:47
von Sirius3
@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)

Re: Schlaufe die sich genau jede Sekunde wiederhohlt

Verfasst: Mittwoch 30. November 2016, 00:28
von snafu
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()