首先我不确定是否应该把这个作为一个Ubuntu问题或这里。 但我猜测这是一个Python问题,而不是一个OS问题。
我的Python应用程序运行在64位核心AMD服务器上的Ubuntu之上。 它通过ctypes
呼叫一个.so来从networking上的5 GigE摄像机中提取图像,然后处理它们。 我在我的应用程序中看到频繁的暂停,导致相机的帧被外部相机库丢弃。
为了进行debugging,我使用了stream行的psutil
Python包,每隔0.2秒在一个单独的线程中注销CPU统计信息。 我在那个线程中睡了0.2秒,当这个睡眠时间更长的时候,我也看到相机的镜头被丢弃了。 我已经看到了长达17秒的停顿! 我的大多数处理是在OpenCV或Numpy(都释放GIL)或在应用程序的一部分multiprocessing.Pool
与59进程(这是为了解决Python的GIL)。
我的debugging日志logging在暂停发生时,在我的进程的很multithreading上显示了非常高的“系统”(即内核)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系统使用率在匹配高stream程系统使用率之前报告一行。 这两者相配以来,64核心的26.4%= 41%。 此时,我的应用程序经历了大约3.5秒的暂停(由我的CPU信息日志logging线程使用OpenCV的cv2.getTickCount()
以及Python日志logging输出中的时间戳记中的跳转)确定导致多个相机帧被丢弃。
发生这种情况时,我也logging了我的进程的每个线程的CPU信息。 对于上面的例子,25个线程在0.9的“系统”CPU利用率下运行,在0.6上运行几个线程,这与以上26.4的处理总量相匹配。 那时候有大约183个线程在运行。
这个暂停通常在多处理池被使用后(它被用于短脉冲)似乎发生,但每次使用该池时都不会发生。 另外,如果我减less需要在池外发生的处理量,则不会发生相机跳过。
问题:我怎么能确定为什么操作系统的系统/内核时间突然通过屋顶? 为什么会在Python应用程序中发生?
更重要的是:为什么会发生这种情况,以及如何避免这种情况?
笔记:
upstart
respawn
),这种情况一天发生多次,所以这不是由于长时间运行,我也看到这个过程很快就开始了 nice
的-2,我已经尝试删除没有影响的nice
好。 我有我自己的问题的答案。 是的,我花了3个多月才弄到这么远。
这似乎是GIL在Python中的颠簸,这是造成大量“系统”CPU峰值和相关暂停的原因。 以下是对颠簸来自何处的一个很好的解释 。 这个介绍也指出了我的正确方向。
Python 3.2 引入了一个新的GIL实现来避免这种抖动。 结果可以用一个简单的线程示例(从上面的演示文稿中获得)显示出来:
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与Python 2.7.9这使用14.7s'用户'CPU和'系统'CPU 13.2s。
Python 3.4使用15.0s的“用户”(略多),但只有0.2s的“系统”。
因此,GIL仍然存在,它仍然运行得像代码单线程一样快,但它避免了Python 2的所有GIL争用,表现为内核(“系统”)CPU时间。 我认为,这个争论是导致原始问题的原因。
CPU问题的另外一个原因是OpenCV / TBB。 完全记录在这个SO问题中 。