Was ist der richtige Weg, um einem Loop-Thread anzuweisen, das Looping zu beenden?
Ich habe ein ziemlich einfaches Programm, das einen bestimmten Host in einer separaten threading.Thread
Klasse anpingt . In dieser Klasse schläft es 60 Sekunden, das wird erneut ausgeführt, bis die Anwendung beendet wird.
Ich möchte einen 'Stop'-Button in meinem implementieren wx.Frame
, um den Loop-Thread zum Stoppen aufzufordern. Es muss den Thread nicht sofort beenden, es kann einfach aufhören zu schleifen, sobald es aufwacht.
Hier ist meine threading
Klasse (Hinweis: Ich habe noch keine Schleife implementiert, aber sie würde wahrscheinlich unter die Ausführungsmethode in PingAssets fallen.)
class PingAssets(threading.Thread):
def __init__(self, threadNum, asset, window):
threading.Thread.__init__(self)
self.threadNum = threadNum
self.window = window
self.asset = asset
def run(self):
config = controller.getConfig()
fmt = config['timefmt']
start_time = datetime.now().strftime(fmt)
try:
if onlinecheck.check_status(self.asset):
status = "online"
else:
status = "offline"
except socket.gaierror:
status = "an invalid asset tag."
msg =("{}: {} is {}. \n".format(start_time, self.asset, status))
wx.CallAfter(self.window.Logger, msg)
Und in meinem wxPyhton-Frame habe ich diese Funktion über eine Start-Schaltfläche aufgerufen:
def CheckAsset(self, asset):
self.count += 1
thread = PingAssets(self.count, asset, self)
self.threads.append(thread)
thread.start()
quelle
do_run
wait
Timeouts mit 0 verwendenDies wurde zuvor auf Stack gefragt. Siehe die folgenden Links:
Grundsätzlich müssen Sie den Thread nur mit einer Stoppfunktion einrichten, die einen Sentinel-Wert festlegt, den der Thread überprüft. In Ihrem Fall muss das Element in Ihrer Schleife den Sentinel-Wert überprüfen, um festzustellen, ob er geändert wurde. Wenn dies der Fall ist, kann die Schleife brechen und der Thread kann absterben.
quelle
Ich habe die anderen Fragen zu Stack gelesen, war aber immer noch ein wenig verwirrt über die Kommunikation zwischen den Klassen. So bin ich damit umgegangen:
Ich verwende eine Liste, um alle meine Threads in der
__init__
Methode meiner wxFrame-Klasse zu speichern:self.threads = []
Wie unter Wie stoppt man einen sich wiederholenden Thread in Python? Ich verwende ein Signal in meiner Thread-Klasse, das
True
beim Initialisieren der Threading-Klasse auf gesetzt wird.class PingAssets(threading.Thread): def __init__(self, threadNum, asset, window): threading.Thread.__init__(self) self.threadNum = threadNum self.window = window self.asset = asset self.signal = True def run(self): while self.signal: do_stuff() sleep()
und ich kann diese Threads stoppen, indem ich über meine Threads iteriere:
def OnStop(self, e): for t in self.threads: t.signal = False
quelle
Ich hatte einen anderen Ansatz. Ich habe eine Thread-Klasse unterklassifiziert und im Konstruktor ein Ereignisobjekt erstellt. Dann habe ich eine benutzerdefinierte join () -Methode geschrieben, die zuerst dieses Ereignis setzt und dann die Version eines Elternteils von sich selbst aufruft.
Hier ist meine Klasse, die ich für die Kommunikation über die serielle Schnittstelle in der wxPython-App verwende:
import wx, threading, serial, Events, Queue class PumpThread(threading.Thread): def __init__ (self, port, queue, parent): super(PumpThread, self).__init__() self.port = port self.queue = queue self.parent = parent self.serial = serial.Serial() self.serial.port = self.port self.serial.timeout = 0.5 self.serial.baudrate = 9600 self.serial.parity = 'N' self.stopRequest = threading.Event() def run (self): try: self.serial.open() except Exception, ex: print ("[ERROR]\tUnable to open port {}".format(self.port)) print ("[ERROR]\t{}\n\n{}".format(ex.message, ex.traceback)) self.stopRequest.set() else: print ("[INFO]\tListening port {}".format(self.port)) self.serial.write("FLOW?\r") while not self.stopRequest.isSet(): msg = '' if not self.queue.empty(): try: command = self.queue.get() self.serial.write(command) except Queue.Empty: continue while self.serial.inWaiting(): char = self.serial.read(1) if '\r' in char and len(msg) > 1: char = '' #~ print('[DATA]\t{}'.format(msg)) event = Events.PumpDataEvent(Events.SERIALRX, wx.ID_ANY, msg) wx.PostEvent(self.parent, event) msg = '' break msg += char self.serial.close() def join (self, timeout=None): self.stopRequest.set() super(PumpThread, self).join(timeout) def SetPort (self, serial): self.serial = serial def Write (self, msg): if self.serial.is_open: self.queue.put(msg) else: print("[ERROR]\tPort {} is not open!".format(self.port)) def Stop(self): if self.isAlive(): self.join()
Die Warteschlange wird zum Senden von Nachrichten an den Port verwendet, und die Hauptschleife nimmt Antworten zurück. Ich habe keine serial.readline () -Methode verwendet, da die Endzeilenzeichen unterschiedlich sind, und ich habe festgestellt, dass die Verwendung von Io-Klassen zu viel Aufhebens macht.
quelle
Hängt davon ab, was Sie in diesem Thread ausführen. Wenn dies Ihr Code ist, können Sie eine Stoppbedingung implementieren (siehe andere Antworten).
Wenn Sie jedoch den Code eines anderen ausführen möchten, sollten Sie einen Prozess abspalten und starten. So was:
import multiprocessing proc = multiprocessing.Process(target=your_proc_function, args=()) proc.start()
Wenn Sie diesen Vorgang jetzt stoppen möchten, senden Sie ihm ein SIGTERM wie folgt:
Und es ist nicht langsam: Sekundenbruchteile. Genießen :)
quelle
Meine Lösung ist:
import threading, time def a(): t = threading.currentThread() while getattr(t, "do_run", True): print('a') time.sleep(1) threading.Thread(target=a, name='228').start() def getThreadByName(name): flex = threading.enumerate() for i in range(0, len(flex)): thread = str(flex[i]) if thread.startswith('<Thread'): tname = thread.split('(')[1].split(',')[0] if tname == name: return flex[i] return 'none' t = getThreadByName('228') time.sleep(5) t.do_run = False t.join()
quelle