0

我有一个 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 使用率正好翻倍。此外,“栏应该已经开始”和“已经在这里”在栏实际更新之前打印。事实上,回调 self.updateBar 在“已经在这里”之后打印输出。

看起来当代码继续执行时,所有的 GUI 事件都被推迟到一切都空闲为止。情况确实如此,因为不仅在进程完成之前栏不会更新,而且整个窗口都会冻结。我尝试过 self.frame.after 的延迟时间短至 10 毫秒,长至 1000 毫秒,但行为没有任何变化。这是因为该进程以某种方式获得了 tkinter 的某些属性,从而阻止了 tkinter 通过其事件循环?在这里切换到线程有帮助吗?

4

1 回答 1

0

我发现出了什么问题。虽然处理按钮按下的命令正在生成一个新进程来完成工作,但它被 somequeue.get() 阻塞并等待工作完成。由于命令处理与 tkinter 的 mainloop() 在同一线程中运行,因此 mainloop() 事件被阻塞,导致此处出现问题。这可以通过将 somequeue.get() 代码移动到另一个在所有工作完成之前不会阻塞的函数来解决。此函数还更新进度条,同时检查队列中的一些标记值,表明所有工作都已完成。

这就是重点。当所有工作完成时,该功能才会阻塞。

于 2013-09-18T21:09:36.640 回答