Problem mit einem Timer

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
iuno
User
Beiträge: 3
Registriert: Freitag 22. Januar 2010, 20:47

Hi,

ich hab wie der Titel schon verrät ein Problem mit nem Timer.
Nun zum Code:

Code: Alles auswählen

import time
from decimal import Decimal, _Zero, _One

def create_timer(interval):
    get_cur_time = lambda: Decimal(str(time.time()))
    sleep = lambda x: (time.sleep(x) if x > _Zero else None)
    last_time = _Zero
    i = 0
    while 1:
        sleep(last_time + interval - get_cur_time())
        last_time = get_cur_time()
        
        yield i
        i += 1

def hz_to_interval(hz):
    return _One / Decimal(str(hz))

if __name__ == "__main__":
    interval = hz_to_interval(600)
    
    last = 0
    t1 = time.time()
    
    for i in create_timer(interval):
        if t1 + 1. < time.time():
            print i - last, time.ctime()
            last = i
            t1 = time.time()
Hier noch die Ausgabe:

Code: Alles auswählen

794 Fri Jan 22 20:56:55 2010
802 Fri Jan 22 20:56:56 2010
801 Fri Jan 22 20:56:57 2010
801 Fri Jan 22 20:56:58 2010
801 Fri Jan 22 20:56:59 2010
801 Fri Jan 22 20:57:00 2010
801 Fri Jan 22 20:57:01 2010
802 Fri Jan 22 20:57:02 2010
801 Fri Jan 22 20:57:03 2010
801 Fri Jan 22 20:57:04 2010
801 Fri Jan 22 20:57:05 2010
801 Fri Jan 22 20:57:06 2010
801 Fri Jan 22 20:57:07 2010
802 Fri Jan 22 20:57:08 2010
801 Fri Jan 22 20:57:09 2010
802 Fri Jan 22 20:57:10 2010
801 Fri Jan 22 20:57:11 2010
801 Fri Jan 22 20:57:12 2010
...
Der Fall, dass in Zeile 10 ein negativer Wert entsteht, trat bei mir höchstens 2-3x pro Sekunde auf.

Wenn ich statt den 600Hz (Zeile 20) andere Zahlen nehme, nähern sich die Iterationen / Sekunde anderen Werten:
170 -> 200
450 -> 400

Bloß wieso?

Vielen dank schonmal im voraus

edit: Es sind auch Verbesserungsvorschläge etc. erwünscht
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Ehrlich gesagt verstehe ich dein Problem noch nicht so richtig. Es wäre nicht schlecht, wenn du etwas genauer beschreiben würdest was das Programm machen soll, was es macht und was du erwartest.

Ein paar Anmerkungen habe ich aber schon:
- Warum benutzt du das Decimal-Modul? Die ganzen Konvertierungen von Zahlen zu Strings zu Decimal sind sehr schlechter Stil. Ich vermute mal, dass du Probleme mit der Division von Integern hattest. Verwende einfach 1.0/hz (Zeile 17). Alternativ kannst du auch mal nach "from __future__ import division" suchen.

- Zeile 10 kannst du ersetzen durch "sleep(max(0, last_time + interval - get_cur_time())". Zeile 6 entfällt dann.

- Statt "while 1" benutze besser "while True". Noch besser ist aber das while durch ein for zu ersetzen: "for i in in itertools.count():". Zeile 14 entfällt dann natürlich.

- Benutze eine main-Funktion, statt alles unter "if __name__ == ..." zu schreiben.

- t1 finde ich einen sehr nichtssagenden Namen ;-)

Mal ganz grob zusammengefasst was ich so auf den ersten Blick gesehen habe.

Bis dann,
Sebastian
Das Leben ist wie ein Tennisball.
iuno
User
Beiträge: 3
Registriert: Freitag 22. Januar 2010, 20:47

Dieser Teil des Programms soll dafür sorgen, dass bestimmter Code wiederholt ausgeführt werden soll und soll dabei dafür sorgen, dass es keine Rolle spielt, wenn einzelne Durchläufe länger dauern.

Natürlich ergibt das Programm so wie ihr es jetzt grad seht keinen Sinn, da ich (der Übersichtlichkeit halber) das Programm auf das wesentliche reduzieren wollte.

Mein Problem beeinträchtigt das Programm nicht, jedoch interessiert es mich woher der "Fehler" kommt. Da ich ja in dem Beispiel mit 600Hz arbeite müsste das Programm ja dafür sorgen, dass der Code höchstens alle 0.0016666... Sekunden ausgeführt wird.
Dabei ist "last_time + interval - get_cur_time()"(Zeile 10) die Zeit, die noch benötigt wird, um von der vom restlichen Programm benötigten Zeit auf die 0.001666 Sek zu kommen.

Der "Fehler" ist einfach die Tatsache, dass das Programm auf 800Hz kommt. Da ich dachte, dass der "Fehler" aufgrund der Ungenauigkeit von floats auftaucht, griff ich auf das Modul decimal zurück (ich kenne die Tatsache, dass 9/4 = 2 ist :cry: ).
Der "Fehler" tritt weiterhin auf...
- Statt "while 1" benutze besser "while True". Noch besser ist aber das while durch ein for zu ersetzen: "for i in in itertools.count():". Zeile 14 entfällt dann natürlich.
Statt der 1 hatte ich da ursprünglich noch die Möglichkeiten ein Limit zu setzten und die Ausführung parallel durch einen anderen Thread zu unterbrechen, was ich aber (um es euch leichter zu machen 8)) wieder entfernt habe. Mit dem True statt 1 hast du natürlich aber recht.
Benutze eine main-Funktion, statt alles unter "if __name__ == ..." zu schreiben.
Hier auch
BlackJack

Ohne es mir näher angeschaut zu haben: sleep() ist nur so genau wie die darunterliegende Plattform bzw. die `sleep()`-Funktion von der verwendeten C-Bibliothek.
iuno
User
Beiträge: 3
Registriert: Freitag 22. Januar 2010, 20:47

Problem gelöst. :D
Die Funktion time.sleep arbeitet nicht genau genug für meine Ansprüche:

Code: Alles auswählen

def test(sec):
    start = time.time()
    time.sleep(sec)
    end = time.time()
    return end - start
test(0.0015) -> 0.00099992752075195313

Muss mich dann halt auf die Suche nach ner Alternative machen.
Trotzdem vielen Dank EyDu und BlackJack

edit: Lösung gefunden
Antworten