Pool von Timern

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
antaeus
User
Beiträge: 48
Registriert: Dienstag 19. September 2006, 10:10

Morgen zusammen!

ich muss eine ganze Reihe von Timern verwalten können. Also habe ich mir gedacht, ich packe die Timer in ein dictionary, damit ich bequem per name auf die Biester zugreifen kann. Dafür habe ich eine Klasse geschrieben, die so aussieht

Code: Alles auswählen

from threading import Timer, Thread

class TimerPool(object):
    
    def __init__(self):
        print "TP: Creating timer pool..."
        self.dict = {}
        # starts the cleaner timer the first time
        self.startCleanerTimer()
    
    # cleaner timer loop
    def startCleanerTimer(self):
        self.cleanerTimer = Timer(10, self.cleaner)
        self.cleanerTimer.start()
    
    # the cleaner
    def cleaner(self):
        print "TP: Cleaner running..."
        count = 0
        for key in self.dict:
            if self.dict[key]: # --> value for key available
                count += 1
                print key
            else: # --> value for key not available, timer deleted, delete dictionary entry
                self.delTimer(key)
        print "TP: " + str(count) + " timer hosted"
        self.startCleanerTimer()
        
    def add(self, name, timer):
        self.dict[name] = timer
        print "TP: Timer " + name + " added..."
        
    def get(self, name):
        return self.dict[name]
        print "TP: Timer " + name + " found..."
    
    def stop(self, name):
        timer = self.get(name)
        timer.cancel()
        print "TP: Timer " + name + " stopped..."
                
    def delTimer(self, name):
        self.stop(name)
        del self.dict[name]
        print "TP: Timer " + name + " deleted..."   
Zwei Fragen dazu:

1.) Was passiert mit einem Timer-Objekt, nachdem es abgelaufen ist? Ich hätte eigentlich gedacht, dass es von der Garbage Collection früher oder später gelöscht würde. Dem ist aber scheinbar nicht so, weil die Timer, die ich in den Pool packe, auch noch nach deren Ablauf da drin zu sein scheinen.

2.) Wie bekomme ich denn sonst die abgelaufenen Timer aus dem Pool? Gibt es z.B. irgendeinen Aufruf den man an den Timer schicken kann und der antwortet dann, ob er schon abgelaufen ist? Weil dann könnte man durch das dictionary laufen, jeden Timer prüfen und dann löschen.

Grüße!
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

antaeus hat geschrieben:1.) Was passiert mit einem Timer-Objekt, nachdem es abgelaufen ist? Ich hätte eigentlich gedacht, dass es von der Garbage Collection früher oder später gelöscht würde. Dem ist aber scheinbar nicht so, weil die Timer, die ich in den Pool packe, auch noch nach deren Ablauf da drin zu sein scheinen.
Die Garbage Collection sammelt nur Objekte ein, auf die du keine Referenz mehr hast, die zwar im Speicher liegen, auf die du aber nicht mehr zugreifen kannst weil du nicht weisst, wohin du greifen musst. :wink: Solange du also eine Referenz auf ein Timer Objekt in deinem Dictionary hast, bleiben die Objekte erhalten.
BlackJack

antaeus hat geschrieben:1.) Was passiert mit einem Timer-Objekt, nachdem es abgelaufen ist? Ich hätte eigentlich gedacht, dass es von der Garbage Collection früher oder später gelöscht würde. Dem ist aber scheinbar nicht so, weil die Timer, die ich in den Pool packe, auch noch nach deren Ablauf da drin zu sein scheinen.
Die Frage hat Rebecca ja schon grundsätzlich beantwortet. Ergänzend dazu: Objekte wissen nichts darüber von wo aus sie referenziert werden. Wenn so ein Timer abgelaufen ist, dann weiss er nicht in welchem Dictionary-Objekt er steckt oder in welcher Liste oder an welche Namen er gebunden ist. Also kann er sich auch nicht selbst aus solchen Strukturen entfernen.

Die `cleaner()` Methode macht so keinen Sinn. Wenn Du über die Schlüssel eines Dictionary iterierst, dann ist zu jedem Schlüssel auch ein Objekt vorhanden. Du testest ob dieses Objekt "wahr" oder "falsch" ist, nicht ob es vorhanden ist, oder nicht. `Timer` sind immer "wahr", der ``else``-Zweig wird also nie ausgeführt. Du musst prüfen ob der `Timer` bereits gestartet wurde und komplett abgelaufen ist, ungefähr so:

Code: Alles auswählen

    def cleaner(self):
        print 'run cleaner...'
        for name, timer in self.timers.items():
            if timer.finished.isSet():
                del self.timers[name]
        print '%d timer hosted' % len(self.timers)
        self._start_cleaner()
Womit Frage 2 beantwortet wäre. :-)

Alternativ dazu könnte man auch eine Methode einführen, die `Timer` erzeugt und startet und dafür sorgt, das diese nach ihrem Ablauf aus dem Pool entfernt werden.

Völlig ungetestet:

Code: Alles auswählen

    def create_timer(self, time, function, args=(), name=None):
        def delete_wrapper():
            function(*args)
            self.delete_timer(name)
        timer = Timer(time, delete_wrapper)
        if name is None:
            name = timer.getName()
        else:
            timer.setName(name)
        self.timers[name] = timer
        timer.start()
        return timer
antaeus
User
Beiträge: 48
Registriert: Dienstag 19. September 2006, 10:10

Super, vielen dank euch beiden... Damit werde ich mein Problem lösen können!
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

mal so am rande...:

Code: Alles auswählen

    def get(self, name):
        return self.dict[name]
        print "TP: Timer " + name + " found..." 
der print wird nie getätigt werden: es wird vorher die funktion beim return abgeschlossen.
http://www.cs.unm.edu/~dlchao/flake/doom/
antaeus
User
Beiträge: 48
Registriert: Dienstag 19. September 2006, 10:10

Ja das stimmt. Den Code oben habe ich schnell runtergeschrieben und nicht großartig getestet. :wink:
Antworten