KeyError in module 'threading' after a successful py.test run
我正在使用py.test运行一组测试。他们通过了。 pp!但我收到此消息:
1 | Exception KeyError: KeyError(4427427920,) in <module 'threading' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.pyc'> ignored |
我应该如何追踪其来源? (我不是直接使用线程,而是在使用gevent。)
我观察到类似的问题,并决定确切地了解发生了什么-让我描述一下我的发现。我希望有人会发现它有用。
短篇故事
它确实与猴子修补
1 2 | import threading import gevent.monkey; gevent.monkey.patch_thread() |
执行时会吐出有关忽略的
的消息
1 2 | (env)czajnik@autosan:~$ python test.py Exception KeyError: KeyError(139924387112272,) in <module 'threading' from '/usr/lib/python2.7/threading.pyc'> ignored |
如果交换导入行,问题就消失了。
很长的故事
我可以在这里停止调试,但是我认为值得了解问题的确切原因。
第一步是找到打印有关被忽略异常的消息的代码。我很难找到它(对
1 2 | /* Call when an exception has occurred but there is no way for Python to handle it. Examples: exception in __del__ or during GC. */ |
在
1 2 3 4 5 6 7 | #0 0x0000000000542c40 in PyErr_WriteUnraisable () #1 0x00000000004af2d3 in Py_Finalize () #2 0x00000000004aa72e in Py_Main () #3 0x00007ffff68e576d in __libc_start_main (main=0x41b980 <main>, argc=2, ubp_av=0x7fffffffe5f8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe5e8) at libc-start.c:226 #4 0x000000000041b9b1 in _start () |
现在我们可以清楚地看到在执行Py_Finalize时引发了异常-此调用负责关闭Python解释器,释放分配的内存等。它在退出之前被调用。
下一步是查看
看着
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class _MainThread(Thread): def _exitfunc(self): self._Thread__stop() t = _pickSomeNonDaemonThread() if t: if __debug__: self._note("%s: waiting for other threads", self) while t: t.join() t = _pickSomeNonDaemonThread() if __debug__: self._note("%s: exiting", self) self._Thread__delete() # Create the main thread object, # and make it available for the interpreter # (Py_Main) as threading._shutdown. _shutdown = _MainThread()._exitfunc |
很明显,
1 2 3 4 5 6 | Traceback (most recent call last): File"/usr/lib/python2.7/threading.py", line 785, in _exitfunc self._Thread__delete() File"/usr/lib/python2.7/threading.py", line 639, in __delete del _active[_get_ident()] KeyError: 26805584 |
现在我们知道抛出异常的确切位置-在
阅读
问题在于,
现在,如果在猴子修补之前加载了
相反,如果在
为确保以正确的顺序导入模块,我在猴子补丁调用之前将以下代码段添加到了我的代码中:
1 2 3 4 | import sys if 'threading' in sys.modules: raise Exception('threading module loaded before patching!') import gevent.monkey; gevent.monkey.patch_thread() |
我希望您发现我的调试故事很有用:)
您可以使用此:
1 2 3 4 5 6 7 | import sys if 'threading' in sys.modules: del sys.modules['threading'] import gevent import gevent.socket import gevent.monkey gevent.monkey.patch_all() |
我在gevent原型脚本中遇到了类似的问题。
Greenlet回调执行得很好,我正在通过g.join()同步回主线程。对于我的问题,我不得不调用gevent.shutdown()来关闭(假设是)集线器。在我手动关闭事件循环后,程序会正确终止,而不会出现该错误。