Thread mit Schleife beenden

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
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

Hallo, habe folgende Frage:

Ich habe ein Programm welches Daten in eine MySQL DB schreibt. Alle ca. halbe Stunde möchte ich die neusten Einträge ausgeben. Die Ausgabe muss vom Hauptprogramm getrennt sein.

Schmutzige und schnelle Lösung:
Ich habe also einen Thread im Hauptthread gestartet der alle 30 Minuten aufwacht, die DB ausließt und ausgibt. Alles schön und gut.
Beende ich nun den Hauptthread per Strg+C läuft der "Ausgabe-Thread" weiter bis er aus dem sleep() kommt.

Lösungsansatz:
Ich mach die Ausgabe per threading.Timer() und wenn ich das Programm beenden möchte, bekommt der Timer ein cancel().

Problem:
Nun möchte ich den Timer aber nicht einmal, sondern wiederkehrend ausführen.

Ich hoffe, ich habe genug Informationen geliefert :)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Du könntest auch im Thread das sleep() kürzer machen und jeweils immer schauen ob schon 30 Minuten vorbei sind.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

Leonidas hat geschrieben:Du könntest auch im Thread das sleep() kürzer machen und jeweils immer schauen ob schon 30 Minuten vorbei sind.
Und dann per Event den Thread beenden? Oder ein böses Global? Was spricht gegen ein Thread der alle paar Sekunden prüft ob er ein Event zum Beenden bekommt und den Timer startet? Falls der Timer ausgelöst wurde, setzt er ein Event welches der Thread überprüft und dann gegebenenfalls den Timer neu startet.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

vielleicht so (gerne auch ohne globale Variablen als Exemplar einer Klasse)?

Code: Alles auswählen

timer = None
canceled = False

def setup_timer():
    global timer; timer = threading.Timer(1800, timer_action)

def timer_action():
    if not canceled: do_the_database_thing(); setup_timer()

def stop_timer():
    timer.cancel(); global canceled; canceled = True
Stefan
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

Sie meinen so?

Code: Alles auswählen

import threading
import time

class Timed():
    
    def hello(self):
        if not self.canceled:
            print "hello, world"
            self.timed.start_timer()
    
    def start_timer(self):
        self.canceled = False
        self.timed = Timed()
        self.t = threading.Timer(5.0, timed.hello)
        self.t.start()
        
    def stop_timer(self):
        self.t.cancel()
        self.canceled = True

timed = Timed()
timed.start_timer()
time.sleep(20)
timed.stop_timer()
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

Ich habe mich mittlerweile für ein Lösung entschieden, bei der ich die komplette sleep time in kleine Teile zerlege und eine Variable überprüfe. Mein Problem ist nun, wie übergebe ich den Modulen mit "Sleepthread" aus dem Hauptprogramm die geänderte Variable? So schaut meine Programmstruktur schematisch aus:

Code: Alles auswählen

Hauptprogramm
  import Modul1
    Modul1
      import Modul2
      import Modul3
        Modul2
          def end_thread():
            thread_run = False
        Modul3
          def end_thread():
            thread_run = False
  for modul in imported_moduls:
    modul.end_thread()
Per sys.modules könnte man sich alle Module ausgeben und dann durch versuchen welches davon ein end_thread besitzt, was ich aber hässlich finde. Gibt es eine elegantere Lösung?
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Warum kein Event, auf das du im Worker Thread mit einem Timeout von 30 Minuten wartest.
This method returns the internal flag on exit, so it will always return True except if a timeout is given and the operation times out.
also:

Code: Alles auswählen

abbruch = threading.Event()
while not abbruch.wait(30*60):
  do_job()
Bottle: Micro Web Framework + Development Blog
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

Das löst doch nicht mein Problem, dass ich den Event vom Hauptprogramm in die geladenen Module übergeben muss, oder?
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

glaslos hat geschrieben:Das löst doch nicht mein Problem, dass ich den Event vom Hauptprogramm in die geladenen Module übergeben muss, oder?
Häh?!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

glaslos hat geschrieben:Das löst doch nicht mein Problem, dass ich den Event vom Hauptprogramm in die geladenen Module übergeben muss, oder?
Wenn etwas auf Modul-Ebene läuft, dann ist es eigentlich ein Zeichen dafür, dass du etwas falsch machst. Du solltest Funktionen und ggf. Klassen verwenden, diese musst du dann eh explizit aufrufen.
Das Leben ist wie ein Tennisball.
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

EyDu hat geschrieben:
glaslos hat geschrieben:Das löst doch nicht mein Problem, dass ich den Event vom Hauptprogramm in die geladenen Module übergeben muss, oder?
Wenn etwas auf Modul-Ebene läuft, dann ist es eigentlich ein Zeichen dafür, dass du etwas falsch machst. Du solltest Funktionen und ggf. Klassen verwenden, diese musst du dann eh explizit aufrufen.
Hm, ich denke ich habe mich falsch ausgedrückt. Ich habe Teile meines Codes in meinem Programm in Files ausgelagert und importiere sie als Module. Dies benötige ich um dem Anwender die Möglichkeit zu geben gewisse Funktionen optional zu laden und damit er eigene Erweiterungen erstellen kann ohne das Hauptprogramm zu verändern. Wie zuvor erwähnt, weiß ich im Hauptprogramm manchmal nicht, welche Module geladen wurden denen ich ein Event übergeben muss wenn ich das Programm beenden möchte.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Du musst ja nur gestarteten Threads den Event übergeben und doch nicht geladenen Modulen. Und welche Threads du startest, kannst du ja vom Hauptprogramm aus kontrollieren (solltest du auf jeden Fall, ansonsten ist das IMHO schlechtes Design).

(Oder hast du etwa Code auf Modul-Ebene, der beim Importieren ausgeführt wird? Wenn ja, wäre das extrem schlechter Code-Stil und ganz allgemein kein gutes Programmdesign.)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@glaslos:
Vllt. solltest Du Dir noch einmal Gedanken zu Deinem Softwaredesign machen, sonst zerfällt Dir die Anwendung in seine Einzelteile. Für Sachen wie dynamische Erweiterungen mit Plugins zur Laufzeit gibt es einige Entwurfsmuster, in Python ist von einem einfachen callback-Mechanismus bis hin zu einem Eventdispatcher mit Observer alles möglich.
Falls Du im Hauptprogramm ein GUI-Toolkit einsetzt, wird der Aufwand geringer, da Du deren Eventloop hierfür nutzen kannst.
Antworten