【问题标题】:TkInter crashes when called through gRPC通过 gRPC 调用 TkInter 时崩溃
【发布时间】:2021-10-10 08:35:29
【问题描述】:

设置

  • macOS 大苏尔
  • Python 3.9.5
  • 主要依赖项
grpcio = "^1.41.0"
grpcio-tools = "^1.41.0"
grpcio-reflection = "^1.41.0"

问题

我有一个使用 TkInter 的简单 Python 脚本,它在命令行模式下工作,但在使用 gRPC 调用模块时崩溃。

代码

TkInter相关代码:

import tkinter as tk
import tkinter.filedialog as tkfiledialog

def main():
    root = tk.Tk()
    
    root.withdraw()
    root.after_idle(prompt, root)
    root.mainloop()

def prompt(root):
    return tkfiledialog.askopenfilename(
        parent=root,
        title="Select Files",
        filety[es=[("All Files", "*")],
        defaultextension=("All Files", "*"),
        multiple=True,
    ) 

gRPC 架构非常标准,我认为不值得发布。 它也与我的客户端实现无关,因为我可以使用 grpcurl 轻松重现崩溃


grpcurl -d '{"dryrun": false, "verbose": false, "startdir": ".", "dironly": false, "filepatterns": "*" }' -plaintext localhost:57728 selectfilesfolders.SelectFilesFolders.SelectFilesFolders

崩溃日志

2021-10-10 16:06:50.147 Python[2855:90390] WARNING: NSWindow drag regions should only be invalidated on the Main Thread! This will throw an exception in the future. Called from (
    0   AppKit                              0x00007fff22e55ed1 -[NSWindow(NSWindow_Theme) _postWindowNeedsToResetDragMarginsUnlessPostingDisabled] + 352
    1   AppKit                              0x00007fff22e40aa2 -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1296
    2   AppKit                              0x00007fff23002c2f -[NSPanel _initContent:styleMask:backing:defer:contentView:] + 50
    3   AppKit                              0x00007fff22e4058b -[NSWindow initWithContentRect:styleMask:backing:defer:] + 42
    4   AppKit                              0x00007fff23002be4 -[NSPanel initWithContentRect:styleMask:backing:defer:] + 64
    5   AppKit                              0x00007fff2384e274 -[NSSavePanel initWithContentRect:styleMask:backing:defer:] + 97
    6   AppKit                              0x00007fff2385636d -[NSOpenPanel initWithContentRect:styleMask:backing:defer:] + 151
    7   AppKit                              0x00007fff2314f0e5 -[NSPanel init] + 75
    8   AppKit                              0x00007fff2384e1f0 -[NSSavePanel init] + 197
    9   AppKit                              0x00007fff23522c3a +[NSSavePanel(Instantiation) _crunchyRawUnbonedPanel] + 58
    10  libtk8.6.dylib                      0x0000000102b97a11 Tk_GetOpenFileObjCmd + 67
    11  libtcl8.6.dylib                     0x00000001029886dc TclNRRunCallbacks + 80
    12  _tkinter.cpython-39-darwin.so       0x0000000102961029 Tkapp_Call + 585
    13  Python                              0x000000010123245d cfunction_call + 125
    14  Python                              0x00000001011f3a3c _PyObject_Call + 140
    15  Python                              0x00000001012c7a73 _PyEval_EvalFrameDefault + 27027
    16  Python                              0x00000001012cab33 _PyEval_EvalCode + 2611
    17  Python                              0x00000001011f3c41 _PyFunction_Vectorcall + 289
    18  Python                              0x00000001012c9e3c call_function + 732
    19  Python                              0x00000001012c7342 _PyEval_EvalFrameDefault + 25186
    20  Python                              0x00000001012cab33 _PyEval_EvalCode + 2611
    21  Python                              0x00000001011f3c41 _PyFunction_Vectorcall + 289
    22  Python                              0x00000001012c9e3c call_function + 732
    23  Python                              0x00000001012c7491 _PyEval_EvalFrameDefault + 25521
    24  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    25  Python                              0x00000001011f5de9 method_vectorcall + 441
    26  Python                              0x00000001012c7a73 _PyEval_EvalFrameDefault + 27027
    27  Python                              0x00000001012cab33 _PyEval_EvalCode + 2611
    28  Python                              0x00000001011f3c41 _PyFunction_Vectorcall + 289
    29  Python                              0x00000001012c7a73 _PyEval_EvalFrameDefault + 27027
    30  Python                              0x00000001012cab33 _PyEval_EvalCode + 2611
    31  Python                              0x00000001011f3c41 _PyFunction_Vectorcall + 289
    32  Python                              0x00000001011f5d42 method_vectorcall + 274
    33  _tkinter.cpython-39-darwin.so       0x0000000102963bb1 PythonCmd + 209
    34  libtcl8.6.dylib                     0x00000001029886dc TclNRRunCallbacks + 80
    35  libtcl8.6.dylib                     0x0000000102a54ed3 AfterProc + 83
    36  libtcl8.6.dylib                     0x0000000102a54570 TclServiceIdle + 87
    37  libtcl8.6.dylib                     0x0000000102a37d27 Tcl_DoOneEvent + 349
    38  libtk8.6.dylib                      0x0000000102b1aa02 MapFrame + 40
    39  libtcl8.6.dylib                     0x0000000102a54570 TclServiceIdle + 87
    40  libtcl8.6.dylib                     0x0000000102a37d27 Tcl_DoOneEvent + 349
    41  _tkinter.cpython-39-darwin.so       0x00000001029633de _tkinter_tkapp_mainloop + 382
    42  Python                              0x00000001011fc3df method_vectorcall_FASTCALL + 335
    43  Python                              0x00000001012c9e3c call_function + 732
    44  Python                              0x00000001012c7342 _PyEval_EvalFrameDefault + 25186
    45  Python                              0x00000001012cab33 _PyEval_EvalCode + 2611
    46  Python                              0x00000001011f3c41 _PyFunction_Vectorcall + 289
    47  Python                              0x00000001011f5cfa method_vectorcall + 202
    48  Python                              0x00000001012c9e3c call_function + 732
    49  Python                              0x00000001012c7363 _PyEval_EvalFrameDefault + 25219
    50  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    51  Python                              0x00000001012c9e3c call_function + 732
    52  Python                              0x00000001012c7342 _PyEval_EvalFrameDefault + 25186
    53  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    54  Python                              0x00000001012c7a73 _PyEval_EvalFrameDefault + 27027
    55  Python                              0x00000001012cab33 _PyEval_EvalCode + 2611
    56  Python                              0x00000001011f3c41 _PyFunction_Vectorcall + 289
    57  Python                              0x00000001012c9e3c call_function + 732
    58  Python                              0x00000001012c7363 _PyEval_EvalFrameDefault + 25219
    59  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    60  Python                              0x00000001011f5cfa method_vectorcall + 202
    61  Python                              0x00000001012c9e3c call_function + 732
    62  Python                              0x00000001012c73fb _PyEval_EvalFrameDefault + 25371
    63  Python                              0x00000001012cab33 _PyEval_EvalCode + 2611
    64  Python                              0x00000001011f3c41 _PyFunction_Vectorcall + 289
    65  Python                              0x00000001012c9e3c call_function + 732
    66  Python                              0x00000001012c73fb _PyEval_EvalFrameDefault + 25371
    67  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    68  Python                              0x00000001012c7a73 _PyEval_EvalFrameDefault + 27027
    69  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    70  Python                              0x00000001012c9e3c call_function + 732
    71  Python                              0x00000001012c7342 _PyEval_EvalFrameDefault + 25186
    72  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    73  Python                              0x00000001012c7a73 _PyEval_EvalFrameDefault + 27027
    74  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    75  Python                              0x00000001012c9e3c call_function + 732
    76  Python                              0x00000001012c7342 _PyEval_EvalFrameDefault + 25186
    77  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    78  Python                              0x00000001012c9e3c call_function + 732
    79  Python                              0x00000001012c7342 _PyEval_EvalFrameDefault + 25186
    80  Python                              0x00000001011f3cb8 function_code_fastcall + 104
    81  Python                              0x00000001011f5d42 method_vectorcall + 274
    82  Python                              0x000000010136ec56 t_bootstrap + 70
    83  Python                              0x0000000101320169 pythread_wrapper + 25
    84  libsystem_pthread.dylib             0x00007fff2052c8fc _pthread_start + 224
    85  libsystem_pthread.dylib             0x00007fff20528443 thread_start + 15
)

解决方法

  • 如果我用任何代码替换 TkInter 部分,一切正常。
  • 通过子进程使用 IPC 调用它也可以工作

问题

我应该如何进行调试,或者这是否表明 TkInter 不适合我的任务?

【问题讨论】:

  • 在窗口被销毁之前,由于mainloop(),gRPC 调用将永远不会返回。
  • @acw1668 这是导致崩溃的原因吗?这是否意味着任何 GUI 程序都必然会因 gRPC 而失败?我假设通常任何本地函数调用都会允许无限期阻塞行为,对吧?

标签: python tkinter grpc


【解决方案1】:

根据this GitHub anwser

这可能是 macOS 特有的线程问题

另一方面,根据 tkinter 的doc。图书馆可能有 特殊事件处理逻辑和线程限制,以及 gRPC Python 使用线程池处理带有 gRPC Core 的传入请求 处理 IO。

通过深入研究该文档,我们发现

一个 Python 解释器可能有许多与之关联的线程。在 Tcl 中, 可以创建多个线程,但每个线程都有一个单独的 Tcl 与之关联的解释器实例。线程还可以创建更多 不是一个解释器实例,尽管每个解释器实例都可以是 仅由创建它的一个线程使用。

tkinter 创建的每个 Tk 对象都包含一个 Tcl 解释器。它也是 跟踪哪个线程创建了该解释器。调用 tkinter 可以由任何 Python 线程制成。在内部,如果呼叫来自 除了创建 Tk 对象的线程之外,一个事件是 发布到解释器的事件队列中,当执行时,结果 返回到调用 Python 线程。

虽然我不是特定平台线程模型方面的专家,但我知道 macOS 使用的是“Grand Central Dispatch”任务队列系统,它隐藏了很多线程池细节,这与 Windows 不同.

因此,如果不深入研究 gRPC 的线程池模型,我不能说从 volatile gRPC 的 I/O 线程调用 Tkinter 小部件是安全的,这些小部件跟踪创建它们的线程。

【讨论】:

    猜你喜欢
    • 2021-08-16
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 2019-02-22
    • 2016-02-11
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多