Seite 1 von 2
Wie kann ich laufenden Thread neu starten?
Verfasst: Montag 25. Oktober 2010, 08:56
von dkell
Hallo
Ich habe ein Programm, welches aufgrund einer Paramtertabelle in einer Datenbank verschiedene Threads startet (Beispielhaft unten vereinfacht dargestellt). Daneben gibt es noch ein Web-Gui (ebenfalls in einem eigenen Thread), welches die Konfiguration der Parametertabelle zulässt.
Nun möchte ich, wenn über das Webgui ein Eintrag in der Tabelle geändert wird, der enstprechende Thread neu gestartet wird. Irgendwie müsste ja dann der entsprechende laufende Thread beendet und neu gestartet werden, aber wie dies vom Hauptprogramm aus bewerkstelligen?
Vielen dank für Infos
Dani
Code: Alles auswählen
import threading
import time
# [ID, Programm, Paramter]
db = [[1, 1, 50], [2, 2, 20]]
class TestThread1 ( threading.Thread ):
def __init__ ( self, tsleep ):
threading.Thread.__init__( self )
self.tsleep = tsleep
def run ( self ):
i = 1
while 1:
time.sleep(self.tsleep)
print "Thread Programm 1: i = %s" % (i)
i = i + 1
class TestThread2 ( threading.Thread ):
def __init__ ( self, tsleep ):
threading.Thread.__init__( self )
self.tsleep = tsleep
def run ( self ):
i = 1
while 1:
time.sleep(self.tsleep)
print "Thread Programm 2: i = %s" % (i)
i = i + 1
Threads = []
for x in db:
if x[1] == 1:
Threads.append ( TestThread1(x[2]) )
elif x[1] == 2:
Threads.append ( TestThread2(x[2]) )
# Threads starten
for t in Threads:
t.start()
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Montag 25. Oktober 2010, 09:18
von BlackJack
@dkell: Threads kann man weder von aussen beenden noch kann man den Thread selbst erneut laufen lassen. Du musst also den Threadcode so schreiben, dass er selber bei bestimmten Bedingungen mit einem "Neustart" reagiert und das ein Neustart der Berechnung keinen Neustart des Threads erfordert.
Also zum Beispiel anstelle des ``while 1:`` auf eine Bedingung prüfen, welche der GUI-Thread von aussen beeinflussen kann und das ganze selbst dann vielleicht wieder in eine "Endlosschleife" einbetten, wenn der Thread nicht abgebrochen werden soll sondern mit anderen Argumenten weiter rechnen soll.
Als "Endlosschleife" ist ``while True:`` IMHO übrigens lesbarer.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 13:36
von Campionissimo
Hallo,
ich habe irgendwie das gleiche Problem!
Ich möchte mehrere Threads neu starten.
Ich habe eine Gui erstellt mit Buttons einen für start und den anderen zum beenden.
Das mit dem beenden funktioniert ganz gut, aber ich kann nicht neu starten. Weil die Threads noch aktiv sind.
ich hae insgesamt 4 threads.
Alle beende ich indem ich nicht mehr in meine While schleife gehe.
While se.Open () and self.keeprunning:
Zum beenden des Programms druecke ich den Button beenden, mit diesem self.keeprunning auf False gesetzt wird.
Wie kann ich alle Threads neu starten, wenn ich danach wieder auf Start drücke.
Vielen Dank
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 13:53
von deets
Campionissimo hat geschrieben:
Wie kann ich alle Threads neu starten, wenn ich danach wieder auf Start drücke.
Auch ein Jahr spaeter bleibt BlackJacks antwort gueltig. Es geht nicht. Du darst deine Threads entweder nicht beenden, oder du startest neue. Einen alten "wiederbeleben" geht nicht - und ist ja auch semantisch von einem neuen nicht wirklich zu unterscheiden.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 14:02
von Campionissimo
Also nur neue !
Was ist wenn jemand 100 mal auf den button beenden drückt und auch wieder startet.
Dann hab ich 400 Threads aktiv.
Dann ist ja das system überlastet oder nicht.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 14:31
von BlackJack
@Campionissimo: Ich denke wenn der Benutzer auf „Beenden” drückt, dann beenden sich die Threads!? Sollten sie jedenfalls, denn sonst müllst Du Dir das System tatsächlich mit Threads zu.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 14:49
von Campionissimo
Beenden tun sich die Threads nicht. Sie führen keine Aktionen mehr aus. Sie verlaufen irgendwohin.
Aber das müsste docj irgendwie funktionieren. Bei anderen Oberflächen kann man doch auch Beenden und wieder starten.
Oder soll ich ein wait einführen ?
Wenn er die Beenden Taste drückt wartet das System einfach und wenn wieder auf start gedrückt wird wird das wait aufgehoben.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 14:50
von Campionissimo
Ich dachte Threads kann man mit einem Tastendruck nicht beenden!
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 15:09
von BlackJack
@Campionissimo: Threads „verlaufen” nicht „irgendwohin”. Es wird der Code ausgeführt den Du geschrieben hast. Entweder läuft der, oder er ist am Ende und damit auch der Thread. Man kann Threads nicht von *aussen* beenden, deshalb muss der Thread selbst dafür sorgen das er sich beendet.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 15:15
von Campionissimo
In den verschiedenen Threads habe ich diese Funktion:
while self.se.isOpen() and self.KeepRunning:
In meiner GUI Oberfläche drücke ich die Beenden Taste. Dann wird self.KeepRunning auf False gesetzt.
Und somit nichts mehr ausgeführt, da mein ganzes Programm in while steht.
Aber beendet habe ich die Threads nicht, weil wenn ich wieder start drücke heisst das die Threads noch aktiv sind.
Und wie kann der Thread selber dafür sorgen, dass er sich beendet?
Vielen Dank
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Samstag 3. September 2011, 20:55
von BlackJack
@Campionissimo: Wenn der Code nach ``while``-Schleife abgearbeitet ist (sofern da überhaupt welcher steht) ist der Thread beendet. Du bekommst anscheinend eine Fehlermeldung im weiteren Verlauf beim Druck auf „Start”? Dann zeig die doch mal.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 09:43
von LivingOn
Die Sache mit
while 1 und
time.sleep() in einem Thread, ist meinen Erfahrungen nach eher suboptimal. Ich versuche wenn möglich immer mit
threading.Timer() zu arbeiten. Die haben den Vorteil, dass sie jederzeit (auch von außen) abbrechbar sind und sich problemlos wieder starten lassen. Der folgende Code entstammt einem meiner Projekte und ist auf das Nötigste reduziert:
Code: Alles auswählen
import threading
class Worker(threading.Thread):
def __init__(self):
super(Worker, self).__init__()
self.timer = None
self.runflag = True
self.lock = threading.Lock()
def run(self):
self.lock.acquire()
if self.runflag:
#
# hier können die "wichtigen" Aufgaben erledigt werden ;-)
#
# nach 10 Sekunden wird self.run gestartet
self.timer = threading.Timer(10, self.run)
self.timer.start()
self.lock.release()
def stop(self):
self.lock.acquire()
self.runflag = False
if self.timer:
self.timer.cancel()
self.lock.release()
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 10:22
von Campionissimo
Danke erstmal für deine Antwort. Schaut schon mal gut aus.
Wegen der if bedingung:
Ich brauch die while schleife, da ich einen seriellen Port einlese.
Wenn er nicht mehr offen sein sollte, werden meine Aktionen nicht mehr ausgeführt.
Wenn ich jetz if habe, dann schaut er nur am Anfang nach. Es kann nicht mehr überprüft werden während des Programms ob der Port offen ist.
Time.sleep() benutze ich um den thread warten zu lassen, während der eine time.sleep hat kann der andere Thread weiter machen also quasi parallel.
Funktioniert das ganze auch wenn ich den Thread schliesse und dann wieder öffne, also das heisst er ist restartable ?
Wenn ich die start und das beenden mit buttons mache ohne das ich das alles neu compiliere.
Wenn ich falsch liege bitte sagen. Ich suche nur einen weg, damit ich die Threads immer wieder neu starten und beenden kann.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 10:28
von Campionissimo
@ BlackJack
hier die Fehlermeldung:
Code: Alles auswählen
Traceback (most recent call last):
File "C:\Ordner\Test\GUI.py", line 991, in buttonClick
self.omodem.start()
File "C:\python25\lib\threading.py", line 436, in start
raise RuntimeError("thread already started")
RuntimeError: thread already started
Wie du sagst beende ich anscheinend doch die Threads. IM jeden Thread habe ich eine While schleife.
"While self.KeepRuninng:"
Wenn ich den Button beenden drücke wird kein Programm mehr weiter geführt, da alles in den While schleifen steht. Aber anscheinend gibt es noch die Thread sonst würde diese Fehlermeldung nicht kommen.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 10:35
von deets
@LivingOn
Wozu denn das gelocke? Das bremst doch nur den cancel-rufenden Thread unnoetig aus in der Laenge der "wichtigen" Arbeit - und bringt nix, da dank dem GIL das umsetzen eines Attributes eh atomar ist. Selbst wenn es das nicht waere, koenntest du immer noch nur den Test und das canceln locken, wenn's denn sein soll.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 12:19
von BlackJack
@Campionissimo: Man kann einen Thread nur einmal starten. Das steht hier aber weiter oben auch schon irgendwo. Du musst einen neuen nehmen.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 17:33
von LivingOn
deets hat geschrieben:@LivingOn
Wozu denn das gelocke? Das bremst doch nur den cancel-rufenden Thread unnoetig aus in der Laenge der "wichtigen" Arbeit - und bringt nix, da dank dem GIL das umsetzen eines Attributes eh atomar ist. Selbst wenn es das nicht waere, koenntest du immer noch nur den Test und das canceln locken, wenn's denn sein soll.
Der Code stammt aus einem meiner Projekte und es war mir dort wichtig, dass während der Thread "arbeitet", kein Abbruch erfolgen sollte. Sicherlich kann man den Lock auf das Nötigste beschränken, dann geht aber ein Teil der Dokumentation flöten: "run() als auch stop() sind als Ganzes atomar!". Während run() läuft, kann nichts unterbrochen werden und während stop() läuft, kann kein run() mehr starten.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 18:21
von deets
Aber damit machst du dir ja die Nebenlaeufigkeit kaputt. Normalerweise wuerde man das nicht so machen wie du (und im uebrigen auch ein Lock immer in einem finally releasen, bzw. mit einem with-statement aquirieren), sondern eben kleinteilig, und wenn man in stop auch noch auf das Ende der laufenden Operation warten mag, dann macht man halt einen Thread.join.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 19:11
von LivingOn
deets hat geschrieben:Aber damit machst du dir ja die Nebenlaeufigkeit kaputt. Normalerweise wuerde man das nicht so machen wie du (und im uebrigen auch ein Lock immer in einem finally releasen, bzw. mit einem with-statement aquirieren), sondern eben kleinteilig, und wenn man in stop auch noch auf das Ende der laufenden Operation warten mag, dann macht man halt einen Thread.join.
Wieso macht man sich damit die Nebenläufigkeit kaputt?
Der Thread läuft parallel zum Hauptprogramm (also nebenläufig). Ob ich nun mit einem join oder Lock auf die aktuelle Operation warte, ist gehupft wie gesprungen. Wenn Exceptions in der Verarbeitung zu erwarten sind, sollte man natürlich im finally das Lock wieder freigeben. Da ich aber nur ein einfaches Beispiel bringen wollte und der Code so wie er da steht keine Exception wirft, halte ich Deine These "immer in einem finally releasen" für ein wenig überzogen. Es gibt viele Möglichkeiten wie man so etwas implementieren kann. Ich maße mir allerdings nicht an, andere Lösungen von vornherein in Frage zu stellen, nur weil sie nicht so funktionieren, wie ich es für richtig halte.
Re: Wie kann ich laufenden Thread neu starten?
Verfasst: Sonntag 4. September 2011, 19:33
von BlackJack
@LivingOn: Also das mit dem ``finally`` würde ich nicht für optional halten. Man weiss eigentlich nie sicher das etwas ausnahmefrei ist. Es kann zum Beispiel immer ein `MemoryError` auftreten. Und in dem Kommentar wo steht, dass dort die Aufgabe erledigt werden kann, ist allgemein *jede* Ausnahme möglich. Also erwartet man an der Stelle auch grundsätzlich das eine Ausnahme auftreten könnte und sollte dementsprechend defensiv programmieren.
Das mit dem Lock ist eine ziemlich sinnfreie Lösung. Das festzustellen ist IMHO nicht anmassend. Das `runflag` kann man nur *vor* dem Start des Threads, oder *nachdem* `run()` bereits abgearbeitet wurde mittels `stop()` auf `False` setzen. Vor dem Start könnte man sich stattdessen auch einfach entscheiden den Thread gar nicht erst zu starten und nach dem abarbeiten ist „anhalten” Unsinn. Die Methode stoppt nichts, auch wenn sie so heisst (und *das* eigentlich gefragt war) sondern ist nur eine umständlichere Art von `join()`, dass es schon gibt. Was genau löst die Methode also?