设置
- 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部件跟踪创建它们的线程。