TkInter在通过gRPC调用时崩溃



设置

  • macOS Big Sur
  • 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
)

变通办法

  • 如果我用ANY代码替换TkInter部分,一切都正常
  • 通过子进程调用IPC也可以

问题

我应该如何进行调试,还是这应该是TkInter不适合我的任务的迹象?

根据这个GitHub anwser

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

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

通过深入研究该文档,我们找到了

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

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

虽然我不是特定于平台的线程模型的专家,但我确实知道macOS正在使用一个"Grand Central Dispatch";任务队列系统隐藏了许多线程池的详细信息,这与Windows不同。

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

最新更新