Seite 1 von 1

Thread mit Schleife beenden

Verfasst: Mittwoch 5. August 2009, 16:26
von glaslos
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 :)

Verfasst: Mittwoch 5. August 2009, 18:54
von Leonidas
Du könntest auch im Thread das sleep() kürzer machen und jeweils immer schauen ob schon 30 Minuten vorbei sind.

Verfasst: Donnerstag 6. August 2009, 09:20
von glaslos
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.

Verfasst: Donnerstag 6. August 2009, 10:14
von sma
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

Verfasst: Donnerstag 6. August 2009, 13:25
von glaslos
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()

Verfasst: Dienstag 1. Dezember 2009, 13:05
von glaslos
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?

Verfasst: Dienstag 1. Dezember 2009, 14:39
von Defnull
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()

Verfasst: Dienstag 1. Dezember 2009, 20:21
von glaslos
Das löst doch nicht mein Problem, dass ich den Event vom Hauptprogramm in die geladenen Module übergeben muss, oder?

Verfasst: Dienstag 1. Dezember 2009, 22:41
von ms4py
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?!

Verfasst: Dienstag 1. Dezember 2009, 22:45
von EyDu
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.

Verfasst: Mittwoch 2. Dezember 2009, 09:42
von glaslos
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.

Verfasst: Mittwoch 2. Dezember 2009, 09:47
von ms4py
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.)

Verfasst: Mittwoch 2. Dezember 2009, 13:43
von jerch
@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.