threading.Thread von aussen beenden,abbrechen oder killen

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.
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Hallo zusammen,

alle paar Wochen steh ich vor dem selben Problem, ich will einen laufenden Thread beenden, weiß aber nicht wie.

Bis jetzt konnte ich noch immer Events oder ähnliche einbauen , damit ich den Thread gezielt beenden konnte. Jetzt habe ich allerdings einen Thread in dem eine massive Rechnung abläuft (Laufzeiten von mehreren Minuten möglich). Der Benutzer sieht im GUI Thread einen Prozessbalken und soll zusätzlich auf abbrechen klicken können, wenn er die Rechnung stoppen will.

Wie beende ich einen Thread der mitten in der Ausführung ist?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Indem du zwischen den Berechnungen abfragst, ob ein Beenden-Event aufgetreten ist. Die Gewichtung von Laufzeit und Reaktionszeit bleibt dann natürlich noch dir überlassen.

Sebastian
Das Leben ist wie ein Tennisball.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Ich nehme an du erbst von threading.Thread, wenn dem so ist, is in deiner run-Methode eine While-Schleife, du ersetzt while True durch while self.meine_var

Code: Alles auswählen

class Xyz(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.ka_iwas = True
    def run(self):
        while self.ka_iwas:
            print 'xyz'
            sleep(1)
    def stop_it(self):
        self.ka_iwas = False
the more they change the more they stay the same
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

So mache ich das ja auch normalerweise, aber jetzt habe ich eine einzige Funktion, die lange Laufzeiten haben.

Code: Alles auswählen

#hier könnte ich den Thread beenden
funktionXYZ(wert) #diese Funktion hat lange Laufzeiten (1s-3min je nach wert)
#hier könnte ich den Thread beenden 
Der Benutzer wird die Abbrechen-Taste drücken wenn die Rechnung mitten in "funktionXYZ" steckt und muss dann das Ergebnis abwarten, obwohl er es nicht mehr will (Core-Last 100%). "funktionXYZ" ist eine Funktion aus einem importierten Modul.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

IoI hat geschrieben:So mache ich das ja auch normalerweise, aber jetzt habe ich eine einzige Funktion, die lange Laufzeiten haben.
Dann geht das nicht. Aber du könntest statt threads das Multiprocessing-Modul nehmen, dessen Prozesse kannst du per .terminate() beenden.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Oder du startest 2 threads

Einen Thread der die Funktion in einem 2. Thread started, den 2. Thread machst du zum Daemon-Thread, dann killst du einfach den 1., sollte gehen oder?
the more they change the more they stay the same
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Code: Alles auswählen

from threading import Thread
import time
from itertools import count 

class Controller(Thread):
    def __init__(self, func, args=None, kwargs=None):
        Thread.__init__(self)
        self.func = func
        self.args = args or []
        self.kwargs = kwargs or {}
        self.running = True
        
    def stop(self):
        self.running = False
    
    def run(self):
        t = Thread(target=self.func, args=self.args, kwargs=self.kwargs)
        t.setDaemon(True)
        t.start()
        
        while self.running:
            time.sleep(0.1)
    

def worker():
    for i in count():
        print i
        time.sleep(0.05)
    
c = Controller(worker)
c.start()


t = time.time()
time.sleep(2)

c.stop()
Funktioniert.
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

jbs hat geschrieben:

Code: Alles auswählen

from threading import Thread
import time
from itertools import count 

class Controller(Thread):
    def __init__(self, func, args=None, kwargs=None):
        Thread.__init__(self)
        self.func = func
        self.args = args or []
        self.kwargs = kwargs or {}
        self.running = True
        
    def stop(self):
        self.running = False
    
    def run(self):
        t = Thread(target=self.func, args=self.args, kwargs=self.kwargs)
        t.setDaemon(True)
        t.start()
        
        while self.running:
            time.sleep(0.1)
    

def worker():
    for i in count():
        print i
        time.sleep(0.05)
    
c = Controller(worker)
c.start()


t = time.time()
time.sleep(2)

c.stop()
Funktioniert.
Leider nicht, du nutzt in dem Skript nur aus, dass der Prozess beendet wird.

hier dein Quelltext mit Anpassung:

Code: Alles auswählen

from threading import Thread
import time
from itertools import count

class Controller(Thread):
    def __init__(self, func, args=None, kwargs=None):
        Thread.__init__(self)
        self.func = func
        self.args = args or []
        self.kwargs = kwargs or {}
        self.running = True
       
    def stop(self):
        self.running = False
   
    def run(self):
        t = Thread(target=self.func, args=self.args, kwargs=self.kwargs)
        t.setDaemon(True)
        t.start()
       
        while self.running:
            time.sleep(0.1)
   

def worker():
    for i in count():
        print i
        time.sleep(0.05)
   
c = Controller(worker)
c.start()


t = time.time()
time.sleep(2)

c.stop()
print "gestoppet!"
c.join()
print "Controller beendet"
while True:
  print "schlafe"
  time.sleep(1)
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Hmm, verdammt, du hast recht :(
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Code: Alles auswählen

import threading
import ctypes
import time

w32 = ctypes.windll.kernel32
THREAD_TERMINATE = 1 # Privilege level for termination

class DummyThread(threading.Thread):

  def __init__(self):
    threading.Thread.__init__(self)
    self.setDaemon(1)

  def run(self):
    self.tid = w32.GetCurrentThreadId()

    while 1:
      print 'Running'
      time.sleep(1)

def kill_thread(threadobj):

  handle = w32.OpenThread(THREAD_TERMINATE, False, threadobj.tid)
  result = w32.TerminateThread(handle, 0)
  w32.CloseHandle(handle)

  return result

if __name__ == "__main__":

  print 'Starting thread...'
  x = DummyThread()
  x.start()

  time.sleep(5)
  print 'Terminating thread...'
  kill_thread(x)

  time.sleep(5)
  print 'Exiting'
Das hab ich hier http://bytes.com/topic/python/answers/3 ... ill-thread gefunden, funtz zumindest schon mal für Windows.
BlackJack

Das das "killen" offiziell nicht vorgesehen ist, sollte übrigens zu denken geben. Das hat ja Gründe. Zum Beispiel das man keinen definierten Zustand garantieren kann, wenn von aussen einfach so ein Thread hart beendet werden kann. Wenn man den "nativen" Thread killt könnte es sogar sein, dass der Python-Interpreter in einem inkonsistenten Zustand ist.
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Aber ich muss doch irgendwie etwas, was ich schon extra in einem eigenen Thread gestartet habe, wieder beenden können. Alles was in dem Thread ist kann weg, weil der User es nicht mehr braucht.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Darii hat geschrieben:
IoI hat geschrieben:So mache ich das ja auch normalerweise, aber jetzt habe ich eine einzige Funktion, die lange Laufzeiten haben.
Dann geht das nicht. Aber du könntest statt threads das Multiprocessing-Modul nehmen, dessen Prozesse kannst du per .terminate() beenden.
Multiprocessing wäre auch noch schneller als Threading
the more they change the more they stay the same
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dav1d hat geschrieben:Multiprocessing wäre auch noch schneller als Threading
Ooch, es gibt schon durchaus Systeme wo das starten von Prozessen hohen Overhead hat, so dass man das nicht prinzipiell sagen kann...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

IoI hat geschrieben:Aber ich muss doch irgendwie etwas, was ich schon extra in einem eigenen Thread gestartet habe, wieder beenden können. Alles was in dem Thread ist kann weg, weil der User es nicht mehr braucht.
Ganz interessant ist an dieser Stelle vielleicht http://java.sun.com/j2se/1.5.0/docs/gui ... ation.html sollte im groben auch für Python gelten.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Leonidas hat geschrieben:
Dav1d hat geschrieben:Multiprocessing wäre auch noch schneller als Threading
Ooch, es gibt schon durchaus Systeme wo das starten von Prozessen hohen Overhead hat, so dass man das nicht prinzipiell sagen kann...
Auf Python bezogen, in 95% aller Fälle
the more they change the more they stay the same
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dav1d hat geschrieben:Auf Python bezogen, in 95% aller Fälle
Du meinst, 95% aller Python-User sind auf Windows order 95% aller Python-User sind auf Linux?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Nein, In 95% aller Fälle ist multiprocessing schneller als Threading, bezogen auf Python
the more they change the more they stay the same
BlackJack

@Dav1d: Kannst Du die Zahl belegen oder ist die einfach nur ausgedacht!?
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Du fragst mich Sachen, ich meine die Zahl (95) mal in einem Vortrag gehört zu haben
Lieg ich denn falsch?
the more they change the more they stay the same
Antworten