为什么我的Python应用程序因系统而停滞不前? / kernel CPU时间

时间:2015-01-07 02:28:03

标签: python linux performance python-multithreading python-multiprocessing

首先,我不确定是否应该将此作为Ubuntu问题或此处发布。 但我猜它更像是一个Python问题,而不是一个OS问题。

我的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

我不知道为什么在匹配高流程系统使用之前会报告一行高OS系统使用情况。 两者相比,64核中的26.4 = 41%。那时我的应用程序经历了大约3.5秒的暂停 (由我的CPU信息记录线程使用OpenCV的cv2.getTickCount()确定,以及Python日志记录输出中的时间戳跳转) 导致多个相机帧被丢弃。

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

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

问题:如何确定操作系统'系统'/内核时间突然出现的原因?为什么会在Python应用程序中发生?

更重要的是:任何想法为什么会发生这种情况以及如何避免它?

注意:

  • upstart
  • 以root用户身份运行(不幸的是,它不得不用于相机库)
  • 当相机关闭时,应用程序重新启动(在upstart中使用respawn)这种情况每天发生多次,因此不是因为长时间运行,我也看到这种情况在进程开始后很快就会发生
  • 反复运行相同的代码,不是因为运行了我的代码的不同分支
  • 目前nice为-2,我尝试删除nice但没有影响
  • Ubuntu 12.04.5 LTS
  • Python 2.7
  • 机器有128GB的内存,我不在附近使用

1 个答案:

答案 0 :(得分:8)

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

似乎是GIL在Python中肆虐,这就是大规模系统的原因。 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())    

在我的Macbook Pro with Python 2.7.9上,它使用了14.7s的用户' CPU和13.2s的系统'中央处理器。

Python 3.4使用了15.0的用户' (略多)但只有0.2s的系统'。

因此,GIL仍然存在,它仍然只运行与代码是单线程时一样快,但它避免了Python 2的所有GIL争用,表现为内核(' system') CPU时间。我认为,这种争论正是造成原始问题的原因。

更新

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