python - 为什么我的 Python 应用程序停滞在 'system'/内核 CPU 时间

标签 python linux performance python-multithreading python-multiprocessing

首先,我不确定是否应该将其作为 Ubuntu 问题发布或发布在这里。 但我猜它更像是一个 Python 问题而不是操作系统问题。

我的 Python 应用程序在 64 核 AMD 服务器上的 Ubuntu 之上运行。 它通过 ctypes 调用 .so 从网络上的 5 个 GigE 相机中提取图像,然后对其进行处理。 我发现我的应用程序频繁暂停,导致来自相机的帧被外部相机库丢弃。

为了对此进行调试,我使用了流行的 psutil Python 包,我使用它在单独的线程中每 0.2 秒注销一次 CPU 统计信息。 我在该线程中休眠了 0.2 秒,当休眠时间大大延长时,我还看到相机帧被丢弃。 我见过长达 17 秒的停顿! 我的大部分处理要么在 OpenCV 或 Numpy(两者都发布 GIL)中,要么在应用程序的一部分 multiprocessing.Pool 有 59 个进程(这是为了绕过 Python GIL)。

当暂停发生时,我的调试日志显示我的许多进程线程上的“系统”(即内核)CPU 时间非常高。

例如。我看到 CPU 时间如下(通常每 0.2 秒一次)然后突然大跳 (“进程”数字在 CPU 利用率中,即 1 个完全使用的 CPU 为 1,Linux top 显示 123% 为 1.2):

Process user | Process system | OS system % | OS idle %
19.9         | 10.5           | 6           | 74 
5.6          | 2.3            | 4           | 87
6.8          | 1.7            | 11          | 75
4.6          | 5.5            | 43          | 52
0.5          | 26.4           | 4           | 90

我不知道为什么在匹配高进程系统使用率之前先报告高操作系统系统使用率。 两者匹配,因为 64 个内核中有 26.4 个 = 41%。那时我的应用程序经历了大约 3.5 秒的暂停 (由我的 CPU 信息日志记录线程使用 OpenCV 的 cv2.getTickCount() 以及 Python 日志记录输出中的时间戳记决定) 导致多个相机帧被丢弃。

发生这种情况时,我还记录了进程中每个线程的 CPU 信息。 对于上面的示例,25 个线程在“系统”CPU 利用率为 0.9 的情况下运行,还有一些线程在 0.6 的情况下运行,这与上述进程的总数 26.4 相匹配。 那时大约有 183 个线程在运行。

这种暂停似乎通常发生在使用多处理池之后(它用于短时间突发),但绝不是每次使用池时都会发生。 此外,如果我将需要在池外发生的处理量减半,则不会发生相机跳过。

问题:我如何确定为什么 OS“系统”/内核时间突然耗尽?为什么在 Python 应用程序中会发生这种情况?

更重要的是:知道为什么会发生这种情况以及如何避免这种情况吗?

注意事项:

  • 这从 upstart
  • 以 root 身份运行(不幸的是,它必须用于相机库)
  • 当相机关闭时,应用程序会重新启动(在 upstart 中使用 respawn),这种情况一天会发生多次,所以这不是因为长时间运行,我也看到这种情况很快就会发生过程开始
  • 这是一遍又一遍地运行相同的代码,这不是因为运行我的代码的不同分支
  • 当前的 nice 为 -2,我已尝试删除 nice 但没有影响
  • Ubuntu 12.04.5 LTS
  • python 2.7
  • 机器有 128GB 的​​内存,我几乎没有用过

最佳答案

好的。我有自己问题的答案。是的,我花了 3 个多月才走到这一步。

这似乎是 Python 中的 GIL 抖动,这是大量“系统”CPU 峰值和相关暂停的原因。这是一个 good explanation of where the thrashing comes from .该演示文稿也为我指明了正确的方向。

Python 3.2 introduced a new GIL implementation以避免这种颠簸。结果可以用一个简单的线程示例显示(取自上面的演示):

from threading import Thread
import psutil

def countdown():
    n = 100000000
    while n > 0:
        n -= 1

t1 = Thread(target=countdown)
t2 = Thread(target=countdown)
t1.start(); t2.start()
t1.join(); t2.join()

print(psutil.Process().cpu_times())    

在我使用 Python 2.7.9 的 Macbook Pro 上,这使用了 14.7s 的“用户”CPU 和 13.2s 的“系统”CPU。

Python 3.4 使用 15.0 秒的“用户”(略多)但仅使用 0.2 秒的“系统”。

因此,GIL 仍然存在,它仍然只运行与单线程代码一样快,但它避免了 Python 2 的所有 GIL 争用,表现为内核(“系统”)CPU 时间。我相信,这种争论是导致原始问题的原因。

更新

发现 CPU 问题的另一个原因是 OpenCV/TBB。完整记录在本 SO question 中.

关于python - 为什么我的 Python 应用程序停滞在 'system'/内核 CPU 时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27810561/

相关文章:

python - session 未创建异常 : Message: Unable to create new service: ChromeDriverService with ChromeDriver and SeleniumGrid through Python

regex - sed 在特定匹配行的末尾附加一些内容

java - 来自 InputStream 的编年史字节

java - 帮助 Neuroph 神经网络

c# - 在 C# 中,++i vs i += 1 有什么性能差异吗?

python - 如何从 __new__ 参数返回子类

python - 为什么尝试更新 geoDjango Point 对象时没有保存任何内容?

python - 在设置关键字参数的默认值时可以引用位置参数吗?

linux - 打开终端时.bash_aliases 文件会创建错误输出

linux - 在 Linux/UNIX 中加入 pthreads 的主要目的是什么?