Python 在后台从另一个类运行函数
我有一个工人班Python 在后台从另一个类运行函数,python,multithreading,tkinter,Python,Multithreading,Tkinter,我有一个工人班 class Parser: #(threading.Thread) ... def longTask(self,...) ... return ... 还有一个窗口类,它使用tkinter class Window: ... def startProcess(self,...): p = Parser() t= threading.Thread(target=p.longTa
class Parser: #(threading.Thread)
...
def longTask(self,...)
...
return
...
还有一个窗口类,它使用tkinter
class Window:
...
def startProcess(self,...):
p = Parser()
t= threading.Thread(target=p.longTask())
t.start()
return
...
但是,即使longTask()在单独的线程中运行,我的GUI也会冻结——为什么
我的目标是在longTask()运行时更新窗口中的progressbar。longTask()在内部更新一个数字,范围从0到100
问题:在longTask()运行时,如何实现这一点并防止GUI冻结
注意:显然,当我调用t.start()时线程不会启动,但是当我通过t=threading.thread…启动线程时,虽然注释中的解决方案可能有效,但我发现在过去,threading确实与tkinter不一致,tkinter有自己的虚拟事件管理器。我写这篇文章是为了,如果你尝试的东西不起作用,你应该能够以这种方式实现它
import tkinter
import tkinter.ttk
import threading
import queue
import time
def long(steps):
time.sleep(1)
for i in range(20):
steps.put(5)
time.sleep(0.2)
class Window:
def __init__(self):
self.steps = queue.Queue()
self.root = tkinter.Tk()
self.root.title("Loading")
self.progressbar = tkinter.ttk.Progressbar(self.root)
self.progressbar.pack(fill="both", padx=10, pady=10)
def update(self):
if self.progressbar["value"] == 100:
self.root.quit()
self.root.destroy()
elif not self.steps.empty():
step = self.steps.get()
self.progressbar["value"] += step # Not progressbar.step because it loops
self.root.after(100, self.update)
def main(self):
self.update()
self.root.mainloop()
window = Window()
t = threading.Thread(target=long, args=(window.steps,))
t.start()
window.main()
当试图让线程对象与tkinter对象进行交互时,使用某种可供两者使用的可变介质效果更好。因为增加加载条的步骤数可以改变,所以我使用了一个队列(它也是线程安全的)。每次发生某些事情时,函数都会将步骤放入队列中,tkinter应用程序有自己的循环来检查是否有任何新步骤,从而有效地调节线程和tkinter之间的交互
这只是防止GUI冻结的另一种方法,而不是修复现有算法的方法。t是驻留在堆栈上的实例,因此在函数调用后,它将尝试调用该对象的释放,这是不可能的。因此,您可以将线程设置为一个成员,比如self.t=threading.thread(target=p.longstask())我已经包含了您的建议,但是为什么在t=threading.thread(…而不是在t.start()上调用longstask呢?应该是
p.longstask
而不是p.longstask()
这也是p.longstask在创建线程之前立即启动,GUI冻结的原因。通常情况下,您只需将函数的引用传递给线程。但您调用函数(使其启动)。将其更改为self.t=threading.thread(target=p.longstask,args=(myArg))