我有一个GUI类,它只包含tkinter小部件的实例,而不是tkinter的子类。此GUI类还有一个数据处理对象的实例,它调用一个需要很长时间才能执行的成员函数。为了防止GUI冻结并更新进度条,我使用了多处理。
outqueue = mp.Queue()
objqueue = mp.Queue()
progqueue = mp.Queue()
try:
process = mp.Process(target=self.vromad.extractPlayers_mp,args=[outqueue, objqueue, progqueue])
process2 = mp.Process(target=self.vromad.extractPlayers)
process2.daemon = True
process.daemon = True
process.start()
process2.start()
print("started process")
self.frame.after(500, self.updateBar, progqueue)
print("bar should have started")
except:
self.exceptionPopUp(traceback.format_exc())
xtractStatus = -1
print("already here")
这是行为真正有趣的地方。我运行第二个进程,它与第一个进程相同,以检查多处理是否有任何阻塞。不,在任务完成之前“开始处理”打印。事实上,通过添加process2.start(),CPU使用率正好翻了一番。此外,在条形图实际更新之前,“bar应该已经开始”并且“已经在这里”被打印。事实上,回调self.updateBar打印输出AFTER“已经在这里。”
在代码继续优异的情况下,所有GUI事件都会延迟,直到所有内容都处于空闲状态。这看起来确实如此,因为在进程完成之前,条形图不仅不会更新,而且整个窗口都会冻结。我已经尝试过self.frame.after的延迟时间,短至10毫秒,长达1000毫秒,行为没有变化。这是因为进程以某种方式得到tkinter的某些属性阻止tkinter通过其事件循环?切换到线程会有帮助吗?
答案 0 :(得分:0)
我发现了什么问题。虽然处理按钮按下的命令产生了一个新的进程来完成工作,但它正在阻塞somequeue.get()并等待工作完成。由于命令处理在与tkinter的mainloop()相同的线程中运行,因此mainloop()事件被阻塞,导致此处出现问题。这可以通过将somequeue.get()代码移动到另一个不会阻塞的函数来解决,直到所有工作都完成。此函数还会更新进度条,同时检查队列中的某些标记值,表明所有工作都已完成。
这是重点。完成所有工作后,该功能会阻止 ONLY 。