调试随机挂起并使用 100% 处理器内核的 Python 脚本

Posted

技术标签:

【中文标题】调试随机挂起并使用 100% 处理器内核的 Python 脚本【英文标题】:Debugging a Python script that randomly hangs and uses 100% of a processor core 【发布时间】:2013-06-03 21:15:42 【问题描述】:

我目前正在编写一个相当复杂的多线程 Python 脚本。有一个主要功能一次在大约 5 个线程中运行。我一直遇到一些问题,它挂起并使用它运行的 100% 的处理器内核。这种挂起发生在 main 函数运行了数百次之后,因此很难准确地确定它发生的时间或地点。一旦程序挂起,它就再也不会开始运行了。

似乎每次只有一个线程挂起,所以我不太明白为什么它会挂起整个程序。那时我发现this Stack Overflow solution 解释说:“在某些 Python 实现中,一次只能执行一个 Python 线程。CPython 中的线程仅对多路复用 IO 操作真正有用,而不是用于将 CPU 密集型任务置于后台。”因此,当一个线程因 CPU 使用率满而挂起时,整个程序就会停止,这是可以理解的。

下面是进程资源管理器在程序挂起时查看 python.exe 进程的屏幕截图。如您所见,实际上只有一个线程在做某事。

我希望能够准确分析在脚本挂起之前执行了哪些行。我真的不知道我可以在哪里使用“import pdb; pdb.set_trace()”插入断点,因为我不知道它何时何地会搞砸。我无法手动单步执行该程序,因为它需要运行 30 分钟到几个小时才能挂起。我尝试查看我的脚本以查找任何可能导致的明显无限循环或类似情况,但我似乎无法弄清楚导致挂起的原因。

我的问题是:我将如何调试它?理想情况下,我只想看看在挂起之前执行了哪些行,但我什至不知道如何检测它何时挂起。我不能在这里发布完整的脚本,所以希望有人知道我可以如何调试它。提前致谢。

【问题讨论】:

和一本好书greenteapress.com/semaphores 一个建议是 Python 中的线程只能在原子操作上阻塞整个程序,例如,如果您正在对非常大的列表进行排序。 使用跟踪模块。 您是否尝试过发送KeyboardInterrupt 并查看回溯的来源? @Marcin 这看起来很有趣。我会试试看它是否有帮助。谢谢! 【参考方案1】:

这可能有助于 src https://softwareengineering.stackexchange.com/questions/126940/debug-multiprocessing-in-python

import multiprocessing, logging
logger = multiprocessing.log_to_stderr()
logger.setLevel(multiprocessing.SUBDEBUG)

【讨论】:

我不确定这是否与我的脚本相关,因为我使用的是线程模块而不是多处理。 在python中,特别是在windows下,没有实现多线程,至少不像其他语言那样,我自己还没有看到一个工作示例,谁知道,但也许是你所有痛苦的原因是多线程和多处理之间的选择【参考方案2】:

您可以尝试 Sys Internals 中的 procmon,以查看您的进程在系统调用级别正在/正在做什么。

您还可以尝试使用调试器进行附加,并了解如何为每个线程获取回溯。我不确定 gdb 在 Windows 上的效果如何,但这是我过去在 *ix 上使用的。即使您附加到 C 程序(cpython 解释器),有时也可以看到 Python 调用堆栈,使用类似 http://svn.python.org/projects/python/trunk/Misc/gdbinit

pdb 可能确实比 gdb 更好,但我没有为此使用 pdb。

【讨论】:

以上是关于调试随机挂起并使用 100% 处理器内核的 Python 脚本的主要内容,如果未能解决你的问题,请参考以下文章

Google 登录 API 挂起并出现未捕获的错误无法从 URL 哈希获取父源

Visual Studio 2010 挂起附加到进程/调试

为啥我与 Apple APNS 的 TCP 连接挂起并强行断开连接

CORS 选项预检悬挂

MvvmCross Xamarin Android 在初始屏幕上挂起并带有链接

Java进程挂起并继续