【问题标题】:Joining process during quitting - Tkinter + multiporcessing退出期间的加入过程 - Tkinter + multiprocessing
【发布时间】:2014-06-18 11:53:49
【问题描述】:

我正在编写一个 GUI 应用程序,该应用程序有一个调用长任务的按钮。为了不冻结 GUI,我使用 python 3.3 的多处理模块将任务委托给不同的进程。然后我使用管道返回结果进行显示。

我希望应用程序即使在计算过程中退出也不会留下任何僵尸进程。由于我在 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,一个用于工作人员)。

如何使它在其他情况下也能正常工作? 这是好习惯吗?是一种更好、更 Python 的方式吗?

另外,在脚本的最后,我有这两行(如果窗口在不处理任何内容的情况下关闭,exit() 将关闭应用程序):

root.mainloop()
exit()

最后,update() 和 mainloop() 有什么区别?只是后者占用了程序,而 update() 没有?

【问题讨论】:

  • 您是否尝试过添加一个例外:在出现异常时手动停止进程的操作?
  • 我刚试过,效果一样。 (我假设说停止您的意思是 p.join())
  • 尝试使用 os.kill(processid,sig) 方法
  • 关闭窗口时有效,但Command+Q无效

标签: python user-interface python-3.x tkinter multiprocessing


【解决方案1】:

我之前遇到过类似的问题(除了我没有使用多进程)。经过近一整天的研究,我得出以下结论:

  1. mainloop 和root.waitwindow 将(有时)阻止 sys.exit 信号,您的程序应该在您点击 ⌘Q 后收到该信号。
  2. 您可以将 ⌘Q 绑定到新函数,尽管您可能仍会收到 sys.exit 信号
  3. 另一种方法(在我的情况下更可靠)是将 tcl 退出信号重新映射到另一个函数,而不是默认函数。您可以使用以下命令重新映射退出事件(停靠退出和⌘Q):root.createcommand('::tk::mac::Quit',function)
  4. 尝试退出软件时,请使用sys.exit 而不是exit() 或quit()
  5. 您还可以使用root.wm_protocol("WM_DELETE_WINDOW", function) 来定义用户单击红色按钮时的行为。
  6. 实际上,您可以通过标记root.overridedirect(1) 使窗口边框和三个默认按钮消失,从而强制用户单击 GUI 上的按钮而不是关闭窗口。

【讨论】:

    【解决方案2】:

    好的,我终于解决了。虽然我不完全确定这种方法的 pythoness 或副作用,但如果有人需要它就在这里。

    我认为正确退出只能发生在 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(),但守护进程似乎解决了僵尸进程问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-11
      • 2016-12-30
      • 2014-03-05
      • 2012-12-21
      • 2018-11-26
      • 1970-01-01
      • 2017-07-14
      • 1970-01-01
      相关资源
      最近更新 更多