【问题标题】:Tkinter Spinbox and multiprocessing causes mac SEGFAULTTkinter Spinbox 和多处理导致 mac SEGFAULT
【发布时间】:2016-01-18 17:42:49
【问题描述】:

在使用多处理和 tkinter 时,我的应用程序在 OSX 上失败了。最简单的例子如下:

import multiprocessing
from tkinter import Spinbox #Delete this line and it works

class Gui(multiprocessing.Process):

    def run(self):
        self.start_window()
        self.root.mainloop()

    def start_window(self):
        from tkinter import Tk
        self.root = Tk()
        self.root.title('Test')

g = Gui()
g.start()

当尝试执行此 sn-p mac 失败并显示以下报告:

过程:Python [1453] 路径:> /Library/Frameworks/Python.framework/Versions/3.4/Resources/Python.app/Contents/MacOS/Python 标识符:Python 版本:3.4.4 (3.4.4) 代码类型:X86-64(本机) 父进程:Python [1452] 责任人:终端[395] 用户 ID:501

日期/时间:2016-01-18 18:33:23.281 +0100 操作系统版本:Mac OS X 10.11.2 (15C50) 报告版本:11 匿名 UUID:49081BD5-7C1E-52F6-E5D9-F9F41BA8DFE5

自启动以来的唤醒时间:6200 秒

系统完整性保护:启用

崩溃的线程:0 调度队列:com.apple.main-thread

异常类型:EXC_BAD_ACCESS (SIGSEGV) 异常代码:0x0000000000000110 处的 KERN_INVALID_ADDRESS

0x110 附近的 VM 区域: --> __TEXT 0000000100000000-0000000100001000 [4K] r-x/rwx SM=COW /Library/Frameworks/Python.framework/Versions/3.4/Resources/Python.app/Contents/MacOS/Python

应用特定信息: * 多线程进程分叉 * 在 fork pre-exec 的子端崩溃

线程 0 崩溃::调度队列:com.apple.main-thread 0 libdispatch.dylib 0x00007fff99f0fd69 _dispatch_async_f_slow + 391

1 libxpc.dylib 0x00007fff8fb8daa0 xpc_connection_resume + 192

2 com.apple.CoreFoundation 0x00007fff9bbb69d1 _CFPrefsWithDaemonConnection + 353

删除 Spinbox 导入(未在代码中使用)使一切运行。同样的问题出现在python 3.4.4和2.7(将tkinter改为Tkinter)

删除多处理模块并使所有内容都在同一个进程上运行也会使问题消失。

我的猜测是我违反了一些 Tk/Tcl 约束,但是我在阅读文档时没有发现任何关于此的内容,而且这种情况仅发生在 Spinbox 而不是 Entry 或其他小部件的事实是可疑的。

【问题讨论】:

  • 在我们提供帮助之前,我们必须知道为什么使用多处理而不是之后。在程序中,你期望 g.start() 做什么?您没有给它任何执行目标,它仅在 mainloop 完成后执行。以及如何使用这种技术执行多个进程,因此不需要多处理。旋转框只是一个条目,可以选择的值数量有限,因此不需要单独的过程。出现问题的原因似乎是技术不佳,如果这是真的,那么您必须获得更好的技术。
  • Doug Hellmann 的多处理基础知识pymotw.com/2/about.html 可能会有所帮助。
  • 这个例子是显示问题的最小python程序,实际上我有9个进程通过ZMQ进行不同的通信。我这样做是为了克服 GIL 的限制。由于 Gui 是 Process 的子类,当我调用 start() 时,Process 安排一切以在新的 Process 中执行 Gui 的 run() 方法。有很多使用 target 的例子,但你也可以找到子类化的工作(在我看来更 OO)
  • 我的疑惑来自于仅仅导入(而不是实际使用)Spinbox 会触发错误,提示该模块在 init 之外有直接指令,这看起来不是很pythonic。但这也发生在非常受限的情况下:Mac OSX 使用默认启动方法,使用 forserver 或 spawn 启动方法似乎可以工作,使用 linux 或 windows 似乎可以工作。

标签: python macos tkinter python-multiprocessing


【解决方案1】:

我设法让它工作,出于某种原因,tkinter 希望被导入到执行它的同一线程/进程中。

当扩展 multiprocess.Proccess 时,新进程代码在 run() 方法中,init 在父进程上执行。因此,将所有导入更改为在 run 方法上本地完成可以解决问题。

示例代码如下:

import multiprocessing

class Gui(multiprocessing.Process):

    def run(self):
        from tkinter import Spinbox # or Tk, or * ....
        self.start_window()
        self.root.mainloop()

    def start_window(self):
        from tkinter import Tk
        self.root = Tk()
        self.root.title('Test')

g = Gui()
g.start()

现在我的应用程序可以在 Windows、Linux 和 Mac 上运行。

【讨论】:

    【解决方案2】:

    当我在 Windows 上从 IDLE 编辑器运行您的代码时,没有错误,但也没有 tk 框,只有 Shell 中的“>>>”提示。当我将代码的结尾放在 if name 子句下时,具体在 multiprocessing doc

    if __name__ == '__main__':
       g = Gui()
       g.start()
    

    会出现一个 tk 框。只有 g.start() 受到如此保护,情况也是如此。在 Mac 上试用一个或两个版本。我不知道这是否是 OSX 上唯一的问题,但它至少可以让您从在其他系统上运行的东西开始。

    【讨论】:

    • 从命令行执行脚本时,如果 name 行没有区别,我可以在 windows 和 linux 上正确运行代码,但 mac 仍然给出错误。我没有 IDLE 可以测试,但问题仍然存在。
    猜你喜欢
    • 2019-09-19
    • 2022-01-13
    • 2011-03-02
    • 2019-08-25
    • 2010-12-25
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多