我写了一个程序的小例子,应该在按下start_button
之后开始运行多批并行线程。此过程只能启动一次,并且在一批线程完成后,应该检查是否该退出。因此,例如,它可以像这样:-在按下stop_button
的过程中,批处理1(10个线程)正在运行。批处理1完成后,程序应在不运行批处理2的情况下停止运行,并返回初始状态(同样可以选择启动此过程)。
但是,在此过程中,GUI似乎根本无法注册点击或任何操作。好像冻结了。因此,我应该以某种方式将执行其任务的线程与执行其任务的GUI分开,但我不知道具体如何。
似乎解决方案是在线程启动后继续在Tkinter主窗口上调用import threading import tkinter as tk import time import random class Blocking(): def __init__(self): self.master = tk.Tk() self.master.geometry("400x400") self.start_button = tk.Button(self.master, command=self.long_task, text='press me to start', state='normal') self.start_button.pack() self.stop_button = tk.Button(self.master, command=self.stop_func, text='press me to stop', state='normal') self.stop_button.pack() self.long_task_was_stopped = False self.master.mainloop() def one_thread(self, thread_index): time.sleep(random.randint(5, 10)) def long_task(self): # will run many batches of parallel one_thread functions on press of start_button self.start_button["state"] = 'disabled' # first batch of threads threads = [] for thread_number in range(0,10): thread = threading.Thread(target=self.one_thread, args=(thread_number,)) threads.append(thread) thread.start() for thread in threads: thread.join() print("First batch over!") # batch over, check if it was stopped print("Stop variable value:", self.long_task_was_stopped) if self.long_task_was_stopped == True: # reset states, quit function self.long_task_was_stopped = False self.start_button["state"] = 'normal' print("Stopped, exiting!") return # second batch of threads threads = [] for thread_number in range(0,10): thread = threading.Thread(target=self.one_thread, args=(thread_number,)) threads.append(thread) thread.start() for thread in threads: thread.join() print("Second batch over!") self.long_task_was_stopped = False self.start_button["state"] = 'normal' print("Done.") return def stop_func(self): print("Trying to stop...") self.long_task_was_stopped = True if __name__ == '__main__': block = Blocking()
EDIT:
update()
,并检查直到所有线程都结束后再进行操作,为此需要某种计数器和threading.Lock()
。这是解决方案。import threading
import tkinter as tk
import time
import random
class Blocking():
def __init__(self):
self.master = tk.Tk()
self.master.geometry("400x400")
self.start_button = tk.Button(self.master, command=self.long_task, text='press me to start', state='normal')
self.start_button.pack()
self.stop_button = tk.Button(self.master, command=self.stop_func, text='press me to stop', state='normal')
self.stop_button.pack()
self.long_task_was_stopped = False
self.LOCK = threading.Lock()
self.count_of_done_threads = 0
self.master.mainloop()
def one_thread(self, thread_index):
time.sleep(random.randint(5, 10))
with self.LOCK:
print("Thread", thread_index, "done.")
self.count_of_done_threads = self.count_of_done_threads +1
def long_task(self): # will run many batches of parallel one_thread functions on press of start_button
self.start_button["state"] = 'disabled'
self.long_task_was_stopped = False
# first batch of threads
threads = []
for thread_number in range(0,10):
thread = threading.Thread(target=self.one_thread, args=(thread_number,))
threads.append(thread)
thread.start()
# wait until threads are done
while 1:
self.master.update()
if self.count_of_done_threads == 10: # 10 here is size of batch
break
self.count_of_done_threads = 0
print("First batch over!")
# batch over, check if it was stopped
print("Stop variable value:", self.long_task_was_stopped)
if self.long_task_was_stopped == True:
# reset states, quit function
self.long_task_was_stopped = False
self.start_button["state"] = 'normal'
print("Stopped, exiting!")
return
# second batch of threads
threads = []
for thread_number in range(0,10):
thread = threading.Thread(target=self.one_thread, args=(thread_number,))
threads.append(thread)
thread.start()
# wait until threads are done
while 1:
self.master.update()
if self.count_of_done_threads == 10:
break
self.count_of_done_threads = 0
print("Second batch over!")
self.long_task_was_stopped = False
self.start_button["state"] = 'normal'
print("Done.")
return
def stop_func(self):
print("Trying to stop...")
self.long_task_was_stopped = True
if __name__ == '__main__':
block = Blocking()
我写了一个程序的小例子,应该在按下start_button后开始运行多批并行线程。此过程只能启动一次,一个之后就可以启动...
您应该使用non-block thread
。只需thread.start()
可以。在official document: