Python 在 futex 调用中挂起
我有一个在生产环境中运行的 Python 守护进程。它使用 7 到 120 个线程。最近,最小的实例(7 个线程)开始显示挂起,而所有其他实例从未显示此类问题。将 strace 附加到 python 进程显示所有线程都在调用 futex FUTEX_WAIT_PRIVATE,因此它们可能试图锁定某些内容。
你会如何调试这样的问题?
请注意,这是一个从闪存运行的生产系统,因此磁盘写入也受到限制。
I have a Python daemon running in production. It employs between 7 and 120 threads. Recently the smallest instance (7 threads) started to show hangs while all other instances never showed this kind of problem. Attaching strace to the python process shows that all threads are calling futex FUTEX_WAIT_PRIVATE, so they are probably trying to lock something.
How would you debug such a problem?
Note that this is a production system running from flash memory, so disk writes are constrained, too.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
观察有一点不正确。一个线程没有调用 futex,而是在持有 gil 的同时进行交换。由于所讨论的机器硬件较低,因此这种交换花费了很长时间并且似乎陷入了僵局。根本问题是内存泄漏。 :-(
The observation was slightly incorrect. One thread wasn't calling futex, but instead swapping while holding the gil. Since the machine in question is low hardware this swapping took very long and seemed to be a deadlock. The underlying problem is a memory leak. :-(
亲爱的 Helmut,我也遇到了同样的问题,一个线程挂在 FUTEXT_WAIT_PRIVATE 上。
看来你已经解决了这个问题。您能否分享有关该解决方案的更多信息?
UPD:
锁的原因终于找到了(至少对于我的情况):这是由于Python中的导入锁造成的。
考虑以下情况:
file1.py:
file2.py:
这里 Go() 中的导入会挂起,因为导入被锁定在主线程中(通过 import file2),直到 Go() 完成后才会被释放。用户将在 strace 中看到 FUTEX_WAIT_PRIVATE 挂起。
为了解决这个问题,将 file2 导入 Do() 函数期间执行的代码并在导入 file2 后运行它:
Dear Helmut, I've the same problem with one thread hanging on FUTEXT_WAIT_PRIVATE.
It seems you have solved the issue. Can you share more information about the solution?
UPD:
The reason for the lock was finally found (at least for my case): it was due to import lock in Python.
Consider following situation:
file1.py:
file2.py:
Here the import in Go() would hang up since the import is locked in the main thread (by import file2) which will not be released until Go() finishes. The user will see in strace hang on FUTEX_WAIT_PRIVATE.
To work around this place the code executed during the import of file2 into Do() function and run it after importing file2: