threading.Event langsam

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
Hand
User
Beiträge: 65
Registriert: Sonntag 28. Januar 2007, 14:28

Hallo, der threading.Event Mechanismus ist ziemlich langsam sobald man den wait befehl mit einem Timeout versieht.

Code: Alles auswählen

import threading
import time

te = threading.Event()

def t1():
    global te, t
    time.sleep(1)
    t=time.clock()
    te.set()

def main():
    global te, t
    te.clear()
    threading.Thread(target=t1).start()
    te.wait(2.5)
    print time.clock()-t

if __name__ == "__main__":
    main()
Mit te.wait(2.5) dauert der Rücksprung um die 32ms
Mit te.wait() nur 0.2ms

Ist das ein Fehler in Python?
Hand
User
Beiträge: 65
Registriert: Sonntag 28. Januar 2007, 14:28

Hallo,

das Problem tritt auch bei threading.Condition auf sobald man einen Timeout setzt.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Wenn ich das richtig sehe hast du einen Fehler in der Verwendung von clock
Du musst es einmal aufrufen damit die Zeit sich von da auf den ersten Aufruf bezieht.

Code: Alles auswählen

In [18]: time.clock?
Type:           builtin_function_or_method
Base Class:     <type 'builtin_function_or_method'>
String Form:    <built-in function clock>
Namespace:      Interactive
Docstring:
    clock() -> floating point number

Return the CPU time or real time since the start of the process or since
the first call to clock().  This has as much precision as the system
records.
Ich habe den Code bei mir mal gestartet und die Zeiten passen...
Hand
User
Beiträge: 65
Registriert: Sonntag 28. Januar 2007, 14:28

Hallo,

daran liegts nicht, als Zeit kommt da immer um die 30ms rause, auch wenn mans in einer Schleife laufen lässt.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Ok, du hast recht, bei mir sind es ~15ms.
Was für ein OS und welches Python nutzt du ?
Bei mir ist's Python 2.5 auf WinXP
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Ich hab mal in die Sourcen von Python speziell "threading.py" geguckt und folgenden Kommentar in class "_Condition" Methode "wait" gefunden:

Code: Alles auswählen

    def wait(self, timeout=None):
        ...
                # Balancing act:  We can't afford a pure busy loop, so we
                # have to sleep; but if we sleep the whole timeout time,
                # we'll be unresponsive.  The scheme here sleeps very
                # little at first, longer as time goes on, but never longer
                # than 20 times per second (or the timeout time remaining).

Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Aus hauptsächlich ästhetischen Gründen habe ich hab mir mal erlaubt dein Benchmarkprogramm zu ändern:

Code: Alles auswählen

#!/usr/bin/python
# coding:utf-8

import threading
import time
import Queue
import platform

def foo(te, q, time_func):
    time.sleep(1)
    # Startzeit 'rausbringen'
    q.put(time_func())
    te.set()
    # Der thread soll nicht gleich abbrechen - sonst stoppen wir das evtl mit
    time.sleep(0.5)
def main():
    te = threading.Event()
    t = 0.
    q = Queue.Queue()
    #time.clock scheint unter linux nicht sehr präzise zu sein:
    t_func = time.time  if platform.system() =="Linux" else time.clock
    te.clear()
    # wozu 'global'?
    time_thread = threading.Thread(target=foo, args=(te, q, t_func,))
    time_thread.start()
    te.wait(2.5)
    if not te.is_set(): print "Event time-out occured"
    if t_func is time.clock: print time.clock() # RTFM!
    else: print t_func() - q.get()
    time_thread.join() # sauberes ende
if __name__ == "__main__":
    main()
Auf meinem Eeepc (~600MHz, Ubuntu 9.04) schwanken die Zahlen ziemlich stark zw. 8ms und ~25ms.
hth. Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das [mod]timeit[/mod]-Modul existiert.

Und wenn man schon per Hand so kleine Zeitinvervalle misst, dann sollte man nicht nur eine Messung durchführen sondern aus vielen den Mittelwert bilden. Und jetzt bitte tausend Messungen durchführen und einzeln Messen, sonder die Gesamtzeit von allen Messungen durch die Anzahl der Messungen dividieren. Die Timer sind nicht so genau, da diese eine relativ geringe Auflösung haben.
Das Leben ist wie ein Tennisball.
BlackJack

Und immer dran denken, das heutzutage die CPU-Leistung oft dynamisch geregelt wird und zum Beispiel erst nach einigen Sekunden Maximalstärke erreicht.
Hand
User
Beiträge: 65
Registriert: Sonntag 28. Januar 2007, 14:28

Zap hat geschrieben:Ok, du hast recht, bei mir sind es ~15ms.
Was für ein OS und welches Python nutzt du ?
Bei mir ist's Python 2.5 auf WinXP
WinXP SP3 Python 2.6

Ich pollo jetzt jede ms eine Variable in einer while..time.sleep Schleife, die vom anderen Thread geändert wird. Sehr unsauber, aber funktioniert ohne diese Schwankungen.

Für normale PC Programme sind die Schwankungen ja okay, aber für Echtzeitnahe Anwendungen tödlich.

Demnächst test ich das ganze mal mit dem "multiprocessing" Modul und Queues.


@b.esser-wisser:
Schöner Code, leider fehlt mir dazu oft die Zeit :roll:
Zuletzt geändert von Hand am Samstag 12. September 2009, 00:55, insgesamt 1-mal geändert.
Hand
User
Beiträge: 65
Registriert: Sonntag 28. Januar 2007, 14:28

Evtl währ Stackless Python auch noch ne Lösung, könnte das ganze zwar in c++ auslagern, dagegen wehre ich mich aber solangs anders geht :P
Antworten