我正在编写一个GUI应用程序,其中有一个调用长任务的按钮。为了不冻结GUI,我使用python 3.3的multiprocessing模块将任务委托给另一个进程。然后我使用Pipe返回结果以供显示。
我希望应用程序不留下任何僵尸进程,即使在计算期间退出。因为我用的是mac电脑,这有两种方式:退出应用程序(Command+Q),或者直接关闭窗口。
下面是链接到GUI中的按钮的函数中的代码:
main_pipe,child_pipe=Pipe()
p=Process(target=worker,args=(child_pipe,data))
p.start()
try:
while not main_pipe.poll():
root.update()
value_array=main_pipe.recv()
finally:
p.join()
这不起作用,应用程序没有响应Command+q,关闭窗口会留下两个僵尸进程在运行(一个用于GUI,一个用于worker)。
如何使它在其他情况下工作?这是好的做法吗?这是一种更好、更蟒化的方法吗?
另外,在脚本的最后,我有这两行(exit()关闭应用程序,如果窗口关闭而不处理任何东西):
root.mainloop()
exit()
最后,update()和mainloop()有什么区别?是不是只有后者占用了程序,而update()没有?
好了,我终于解决了。虽然我不完全确定关于这个方法的python或副作用,如果有人需要它在这里。
我认为正确退出只能在mainloop()中发生,而不是在update()中发生,所以我写了两个函数,一个用于创建进程,一个用于检查它的输出,它们使用root.after()相互调用。我将进程守护标志设置为true,以确保适当的退出行为。下面是代码:
def process_start():
global value_array
global main_pipe
main_pipe,child_pipe = Pipe()
p=Process(target=worker,args=(child_pipe,data))
p.daemon=True
p.start()
root.after(500,check_proc)
def check_proc():
if not main_pipe.poll():
root.after(500,check_proc)
else:
global value_array
value_array=main_pipe.recv()
我仍然不确定是否需要p.join(),但恶魔的事情似乎绕过僵尸进程的问题
我之前遇到过类似的问题(除了我没有使用多进程)。经过将近一整天的研究,我得出了以下结论:
- mainloop和
root.waitwindow
将(有时)阻塞sys。退出信号,您的程序应在单击⌘Q后接收该信号。 - 您可以将⌘Q绑定到新功能,尽管您可能仍然会收到sys。退出信号
- 另一种方法(对我来说更可靠)是将tcl退出信号重新映射到另一个函数,而不是默认的函数。您可以使用以下命令重新映射退出事件(dock quit和⌘Q):
root.createcommand('::tk::mac::Quit',function)
- 当试图退出软件时,使用
sys.exit
代替exit()
或quit()
- 您还可以使用
root.wm_protocol("WM_DELETE_WINDOW", function)
来定义当用户点击红色按钮时的行为。 - 你实际上可以通过标记
root.overridedirect(1)
使窗口的边界和三个默认按钮消失,从而迫使用户点击GUI上的按钮而不是关闭窗口。