如何给守护线程一个停止事件
How to give a daemon thread a stop event
我正在努力了解 python 中的线程,我拼凑了一个简单的 tkinter UI 可以 运行 后台任务以更好地理解它是如何工作的.
我似乎已经到了可以创建一个单独的线程并与 GUI 交互的地步,但是当我第二次尝试执行任务时问题就来了。
我相信我缺少的是一种告诉守护进程何时停止线程的方法。
到目前为止,这是我的代码:
import threading
import tkinter as tk
from collections import deque
from threading import Thread
from random import randint
from time import sleep
class Emitter:
def __init__(self):
self.stop_event = threading.Event()
self.thread = Thread(target=self.emit_text)
self.running = False
def emit_text(self):
sleep(3)
messageQueue.append(f'Random number: {randint(0, 100)}')
# self.thread.set()
def start_emit(self):
ui.consume_text()
self.thread.setDaemon(True)
self.thread.start()
class UI:
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(self.root, text='Original text')
self.label.pack()
start = tk.Button(self.root, text='Start Download', command=lambda x=Emitter(): x.start_emit())
start.pack()
def consume_text(self):
try:
self.label['text'] = messageQueue.popleft()
except IndexError:
self.root.after(ms=1000, func=self.consume_text)
messageQueue = deque()
ui = UI()
ui.root.mainloop()
我试图理解其他答案,但我无法理解你是如何告诉 daemon/thread 它停止的条件是什么。
该程序在您第一次单击按钮时按预期工作,但如果您再次尝试单击它,它会给出错误 RuntimeError: cannot set daemon status of active thread
,即使我已经等待发射器完成它的任务
感谢@Solomon Slow 的评论,我遇到的问题是我试图重新启动线程,但实际上我应该每次都创建一个新线程。
为了解决这个问题,我更改了 class 发射器 class 以在每次调用 start_emit() 时创建一个新线程。
固定的class:
class Emitter:
def __init__(self):
self.stop_event = threading.Event()
def emit_text(self):
sleep(3)
messageQueue.append(f'Random number: {randint(0, 100)}')
def start_emit(self):
ui.consume_text()
thread = Thread(target=self.emit_text)
thread.start()
我还删除了 self.thread.setDaemon(True)
行。
我正在努力了解 python 中的线程,我拼凑了一个简单的 tkinter UI 可以 运行 后台任务以更好地理解它是如何工作的.
我似乎已经到了可以创建一个单独的线程并与 GUI 交互的地步,但是当我第二次尝试执行任务时问题就来了。
我相信我缺少的是一种告诉守护进程何时停止线程的方法。
到目前为止,这是我的代码:
import threading
import tkinter as tk
from collections import deque
from threading import Thread
from random import randint
from time import sleep
class Emitter:
def __init__(self):
self.stop_event = threading.Event()
self.thread = Thread(target=self.emit_text)
self.running = False
def emit_text(self):
sleep(3)
messageQueue.append(f'Random number: {randint(0, 100)}')
# self.thread.set()
def start_emit(self):
ui.consume_text()
self.thread.setDaemon(True)
self.thread.start()
class UI:
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(self.root, text='Original text')
self.label.pack()
start = tk.Button(self.root, text='Start Download', command=lambda x=Emitter(): x.start_emit())
start.pack()
def consume_text(self):
try:
self.label['text'] = messageQueue.popleft()
except IndexError:
self.root.after(ms=1000, func=self.consume_text)
messageQueue = deque()
ui = UI()
ui.root.mainloop()
我试图理解其他答案,但我无法理解你是如何告诉 daemon/thread 它停止的条件是什么。
该程序在您第一次单击按钮时按预期工作,但如果您再次尝试单击它,它会给出错误 RuntimeError: cannot set daemon status of active thread
,即使我已经等待发射器完成它的任务
感谢@Solomon Slow 的评论,我遇到的问题是我试图重新启动线程,但实际上我应该每次都创建一个新线程。
为了解决这个问题,我更改了 class 发射器 class 以在每次调用 start_emit() 时创建一个新线程。
固定的class:
class Emitter:
def __init__(self):
self.stop_event = threading.Event()
def emit_text(self):
sleep(3)
messageQueue.append(f'Random number: {randint(0, 100)}')
def start_emit(self):
ui.consume_text()
thread = Thread(target=self.emit_text)
thread.start()
我还删除了 self.thread.setDaemon(True)
行。