Python/OpenCV应用程序锁定问题

Dam*_*ria 19 python multithreading opencv multiprocessing

在64核Linux机器上运行的我的Python应用程序通常运行没有问题.然后经过一段随机的时间(通常约0.5到1.5天),我突然开始频繁停顿/锁定超过10秒!在这些锁定期间,系统CPU时间(即内核中的时间)可能超过90%(是的:所有64个核心中的90%,而不仅仅是一个CPU).

我的应用程序经常在一天内重新启动.重新启动应用程序无法解决问题.但是,重新启动机器会.

问题1:什么可能导致90%的系统CPU时间10秒?所有系统CPU时间都在我的父Python进程中,而不是在通过Python的多处理或其他进程创建的子进程中.所以这意味着在内核中花费10+秒的60多个线程的顺序.我甚至不确定这是Python问题还是Linux内核问题.

问题2:重新启动修复问题必须是一个重要的线索.在我的应用程序重新启动之间,系统上的Linux资源可能会耗尽,但不会在重新启动之间耗尽,这可能会导致此问题陷入困境?

到目前为止我已经尝试过解决这个问题/搞清楚了

下面我将提到很多处理.这是因为应用程序在一个循环中运行,而多处理仅在循环的一个部分中使用.所有多处理调用完成,高CPU几乎总会立即发生.我不确定这是暗示原因还是红鲱鱼.

  • 我的应用程序运行一个线程,用于psutil每0.5秒注销一次进程和系统CPU统计信息.我已经独立确认了它的报道内容top.
  • 我已经将我的应用程序从Python 2.7转换为Python 3.4,因为Python 3.2获得了一个新的GIL实现,并且3.4重写了多处理.虽然这改善了一些事情但它并没有解决问题(参见我之前提出的SO问题,因为它仍然是一个有用的答案,如果不是全部答案).
  • 我已经取代了操作系统.最初它是Ubuntu 12 LTS,现在它是CentOS 7.没有区别.
  • 事实证明,在Python/Linux的多线程和多冲突,因此不推荐在一起,Python的3.4现在已经forkserverspawn多语境.我试过它们,没有区别.
  • 我检查了/ dev/shm,看看我的共享内存是否用完(Python 3.4用来管理多处理),没有
  • lsof输出列出所有资源在这里
  • 很难在其他机器上进行测试,因为我运行了一个由59个孩子组成的多进程池,我没有任何其他64个核心机器只是躺在
  • 我无法使用线程而不是进程来运行它,因为它由于GIL而无法快速运行(因此我首先切换到多处理)
  • 我试过只使用strace一个运行缓慢的线程(它不能在所有线程上运行,因为它会使应用程序运行得太慢).以下是我得到的,并没有告诉我太多.
  • ltrace不起作用,因为你不能使用-p线程ID.即使只是在主线程上运行它(否-f)会使应用程序变得如此缓慢以至于问题不会出现.
  • 问题与负载无关.它有时在满载时运行良好,然后在半载时,它会突然出现这个问题.
  • 即使我每晚重启机器,问题也会每隔几天就会发生.

环境/注意事项:

  • Python 3.4.3从源代码编译
  • CentOS 7完全是最新的.uname -a:Linux 3.10.0-229.4.2.el7.x86_64#1 SMP Wed May 13 10:06:09 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux(尽管此内核更新仅在今天应用)
  • 机器有128GB的内存,并有足够的免费
  • 我使用numpy链接到ATLAS.我知道,OpenBLAS冲突与Python多,但ATLAS不,这是冲突被Python 3.4的解决forkserverspawn我已经试过了.
  • 我使用OpenCV,它也做了很多并行工作
  • ctypes用来访问相机制造商提供的C .so库
  • 应用程序以root身份运行(我链接到的C库的要求)
  • Python多处理Poolif __name__ == "__main__":在主线程中保护的代码中创建的

更新了strace结果

有几次我设法在100%'系统'CPU上运行一个线程.但只有一次我从中获得了任何有意义的东西.请参阅下面的电话:10:24:12.446614,需要1.4秒.鉴于它是相同的ID(0x7f05e4d1072c),你在大多数其他调用中看到我的猜测是这是Python的GIL同步.这个猜测有意义吗?如果是这样,那么问题是为什么等待需要1.4秒?有人不发布GIL吗?

10:24:12.375456 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.000823>
10:24:12.377076 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.002419>
10:24:12.379588 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.001898>
10:24:12.382324 sched_yield()           = 0 <0.000186>
10:24:12.382596 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.004023>
10:24:12.387029 sched_yield()           = 0 <0.000175>
10:24:12.387279 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.054431>
10:24:12.442018 sched_yield()           = 0 <0.000050>
10:24:12.442157 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.003902>
10:24:12.446168 futex(0x7f05e4d1022c, FUTEX_WAKE, 1) = 1 <0.000052>
10:24:12.446316 futex(0x7f05e4d11cac, FUTEX_WAKE, 1) = 1 <0.000056>
10:24:12.446614 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <1.439739>
10:24:13.886513 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.002381>
10:24:13.889079 sched_yield()           = 0 <0.000016>
10:24:13.889135 sched_yield()           = 0 <0.000049>
10:24:13.889244 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.032761>
10:24:13.922147 sched_yield()           = 0 <0.000020>
10:24:13.922285 sched_yield()           = 0 <0.000104>
10:24:13.923628 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.002320>
10:24:13.926090 sched_yield()           = 0 <0.000018>
10:24:13.926244 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.000265>
10:24:13.926667 sched_yield()           = 0 <0.000027>
10:24:13.926775 sched_yield()           = 0 <0.000042>
10:24:13.926964 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000117>
10:24:13.927241 futex(0x7f05e4d110ac, FUTEX_WAKE, 1) = 1 <0.000099>
10:24:13.927455 futex(0x7f05e4d11d2c, FUTEX_WAKE, 1) = 1 <0.000186>
10:24:13.931318 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.000678>
Run Code Online (Sandbox Code Playgroud)

Dam*_*ria 0

gdb我已经成功地从 40 多个线程显示 100%“系统”CPU 时间的位置获取了线程转储。

以下是每个线程的回溯:

#0  0x00007fffebe9b407 in cv::ThresholdRunner::operator()(cv::Range const&) const () from /usr/local/lib/libopencv_imgproc.so.3.0
#1  0x00007fffecfe44a0 in tbb::interface6::internal::start_for<tbb::blocked_range<int>, (anonymous namespace)::ProxyLoopBody, tbb::auto_partitioner const>::execute() () from /usr/local/lib/libopencv_core.so.3.0
#2  0x00007fffe967496a in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::local_wait_for_all(tbb::task&, tbb::task*) () from /lib64/libtbb.so.2
#3  0x00007fffe96705a6 in tbb::internal::arena::process(tbb::internal::generic_scheduler&) () from /lib64/libtbb.so.2
#4  0x00007fffe966fc6b in tbb::internal::market::process(rml::job&) () from /lib64/libtbb.so.2
#5  0x00007fffe966d65f in tbb::internal::rml::private_worker::run() () from /lib64/libtbb.so.2
#6  0x00007fffe966d859 in tbb::internal::rml::private_worker::thread_routine(void*) () from /lib64/libtbb.so.2
#7  0x00007ffff76e9df5 in start_thread () from /lib64/libpthread.so.0
#8  0x00007ffff6d0e1ad in clone () from /lib64/libc.so.6
Run Code Online (Sandbox Code Playgroud)

我最初的问题将 Python 和 Linux 放在前面和中心,但问题似乎在于 TBB 和/或 OpenCV。由于 OpenCV 与 TBB 的使用如此广泛,我认为它还必须以某种方式涉及与我的特定环境的相互作用。也许是因为它是 64 核机器?

我在关闭TBB的情况下重新编译了OpenCV,到目前为止问题还没有再次出现。但我的应用程序现在运行速度变慢。

我已将其作为 OpenCV 的错误发布,并将使用由此产生的任何内容更新此答案。