为什么我的Python应用程序被';系统';/内核CPU时间
首先,我不确定我是应该把它作为Ubuntu的问题发布,还是在这里发布。 但我猜这更像是一个Python问题,而不是操作系统问题 我的Python应用程序运行在64核AMD服务器上的Ubuntu之上。 它通过网络调用a.so,通过为什么我的Python应用程序被';系统';/内核CPU时间,python,linux,performance,python-multithreading,python-multiprocessing,Python,Linux,Performance,Python Multithreading,Python Multiprocessing,首先,我不确定我是应该把它作为Ubuntu的问题发布,还是在这里发布。 但我猜这更像是一个Python问题,而不是操作系统问题 我的Python应用程序运行在64核AMD服务器上的Ubuntu之上。 它通过网络调用a.so,通过ctypes从5个GigE摄像机中提取图像,然后对其进行处理。 我看到我的应用程序中经常出现暂停,导致外部相机库丢弃来自相机的帧 为了调试这一点,我使用了流行的psutilPython包,在一个单独的线程中每隔0.2秒注销一次CPU统计数据。 我在这个线程中睡眠0.2秒,
ctypes
从5个GigE摄像机中提取图像,然后对其进行处理。
我看到我的应用程序中经常出现暂停,导致外部相机库丢弃来自相机的帧
为了调试这一点,我使用了流行的psutil
Python包,在一个单独的线程中每隔0.2秒注销一次CPU统计数据。
我在这个线程中睡眠0.2秒,当睡眠时间长得多的时候,我也会看到相机的帧被丢弃。
我见过长达17秒的停顿!
我的大部分处理是在OpenCV或Numpy(两者都发布GIL)中进行的,或者是在应用程序a的一部分中进行的multiprocessing.Pool
有59个进程(这需要绕过Python GIL)
我的调试日志显示,当暂停发生时,我的许多进程线程上的“系统”(即内核)CPU时间非常长
比如说。我看到CPU时间如下(通常每0.2秒一次),然后突然一个大跳跃
(“进程”数字以CPU利用率为单位,即1个CPU充分利用率为1,Linuxtop
显示123%的CPU利用率为1.2):
我不知道为什么高操作系统使用率会在匹配高进程系统使用率之前报告一行。
由于64个核中有26.4个核=41%,因此这两个核匹配。此时,我的应用程序经历了大约3.5秒的暂停
(由我的CPU信息日志记录线程使用OpenCV的cv2.getTickCount()
以及Python日志记录输出中的跳转时间戳确定)
导致多个相机帧被丢弃
发生这种情况时,我还记录了进程中每个线程的CPU信息。
对于上面的示例,25个线程在“系统”CPU利用率为0.9的情况下运行,还有一些线程在0.6的情况下运行,这与上面26.4的进程的总数相匹配。
当时大约有183个线程在运行
这种暂停似乎通常在使用多处理池(用于短突发)之后发生,但决不是每次使用池时都发生。
此外,如果我将需要在池外进行的处理量减半,则不会发生相机跳过
问:我如何确定为什么操作系统的“系统”和内核时间突然飙升?为什么在Python应用程序中会发生这种情况
更重要的是:你知道为什么会发生这种情况以及如何避免吗
注:
- 它以根用户身份运行(不幸的是,对于摄影机库,它必须以根用户身份运行)来自
upstart
- 当摄像头关闭时,应用程序会重新启动(使用upstart中的
),这种情况一天会发生多次,所以这不是因为长时间运行,我也看到过这种情况在流程启动后很快发生respawn
- 这是相同的代码被反复运行,这不是因为运行我的代码的不同分支
- 当前的
为-2,我已尝试删除nice
,但没有任何影响nice
- Ubuntu 12.04.5 LTS
- Python 2.7
- 这台机器有128GB的内存,我根本用不着
- 好的。我有我自己问题的答案。是的,我花了三个多月才走到这一步
在Python中,似乎是GIL的重击,这就是造成大量“系统”CPU峰值和相关暂停的原因。这是一本书。那次发言也为我指明了正确的方向
Python3.2以避免这种颠簸。结果可以通过一个简单的线程示例显示(取自上面的演示):
在使用Python 2.7.9的Macbook Pro上,它使用14.7秒的“用户”CPU和13.2秒的“系统”CPU
Python3.4使用了15.0的“用户”(略多),但只使用了0.2的“系统”
因此,GIL仍然存在,它的运行速度仍然与代码为单线程时一样快,但它避免了Python 2中所有以内核(“系统”)CPU时间表示的GIL争用。我认为,这一论点正是引起最初问题的原因
更新
CPU问题的另一个原因是OpenCV/TBB。这篇文章中有完整的文档。您是否尝试过评测以查看代码在哪里花费时间?cProfile只是单线程的,而Yappi是多线程的,我听说它会导致挂起。我必须为每个线程添加一个cProfiler,收集它们的统计数据,并协调清除它们,因为我只需要在这些偶尔的暂停期间使用配置文件统计数据(经常这样做会在正常运行的噪音中丢失答案)。可以尝试,但听起来有问题。如果没有别的事,我想我会去那里。
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
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())