1. 程式人生 > python > Python / OpenCV應用程式鎖定問題

【python】Python / OpenCV應用程式鎖定問題

我的python應用程式執行在64核Linux裝置上,執行正常,沒有問題。然後,經過一段隨機的時間(通常在0.5到1.5天左右),我突然開始頻繁地暫停/鎖定超過10秒!在這些鎖定期間,系統CPU時間(即核心中的時間)可以超過90%(是:64個核心中的90%,而不是一個CPU)。
我的應用程式每天都會重新啟動。重新啟動應用程式並不能解決問題。但是,重新啟動計算機確實如此。
問題1:什麼會導致90%的系統CPU時間持續10秒?所有的系統CPU時間都在我的父python程序中,而不是在通過python的多程序或其他程序建立的子程序中。這意味著60多個執行緒在核心中花費了10秒以上的時間。我甚至不確定這是Python問題還是Linux核心問題。
問題2:重啟修復了問題,這一定是導致問題的一個重要線索。在我的應用程式重新啟動之間,而不是在重新啟動之間,系統上的哪些Linux資源可能會耗盡,這可能會導致此問題無法解決?
我到目前為止一直在努力解決這個問題
下面我將提到很多多處理。這是因為應用程式在一個迴圈中執行,而多處理只在迴圈的一部分中使用。高CPU幾乎總是在所有多處理呼叫完成後立即發生。我不確定這是一個暗示,還是一個紅鯡魚。
我的應用程式執行一個執行緒,該執行緒使用psutil每0.5秒登出一次程序和系統CPU狀態。我已經獨立地用top確認了它報告的內容。
我已經將我的應用程式從python 2.7轉換為python 3.4,因為python3.2有了一個新的gil實現,3.4重寫了多處理。雖然這改進了一些事情,但並沒有解決問題(請參閱my previous SO question我要離開,因為它仍然是一個有用的答案,如果不是全部答案的話)。
我已經更換了作業系統。最初是Ubuntu12LTS,現在是Centos7。沒有區別。
事實證明,在python/linux中多執行緒和多處理髮生衝突,不建議同時使用,python 3.4現在具有forkserverspawn多處理上下文。我試過了,沒什麼區別。
我檢查了/dev/shm以檢視是否耗盡了共享記憶體(python 3.4用來管理多處理),什麼都沒有。
lsof輸出列出所有資源here
在其他機器上測試是很困難的,因為我運行了一個由59個孩子組成的多程序池,而且我沒有任何其他64個核心機器只是躺在那裡。
我不能用執行緒而不是程序來執行它,因為由於gil的原因,它不能足夠快地執行(因此,我首先選擇了多處理)
我只在一個執行緩慢的執行緒上使用了strace(它不能在所有執行緒上執行,因為它會使應用程式執行得太慢)。下面是我所得到的,這並沒有告訴我多少。
ltrace不起作用,因為您不能線上程ID上使用-p。即使只是在主執行緒上執行它(沒有-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的記憶體,並且有足夠的空閒空間
我用的是與Atlas相關的numpy。我知道openblas與python多處理衝突,但atlas沒有衝突,我嘗試過的python 3.4的forkserverspawn解決了衝突。
我用的是opencv,它也可以做很多並行工作。
我使用ctypes訪問相機制造商提供的c.so庫
應用程式作為根執行(我連結到的C庫的要求)
python multiprocessingPool是在由if __name__ == "__main__":保護的程式碼和主執行緒中建立的。
更新了strace結果
有幾次,我設法找到了一個以100%的“系統”CPU執行的執行緒。但只有一次我從中得到了有意義的東西。請參見下面10:24:12.446614的通話,需要1.4秒。考慮到它是相同的ID(0x7f05e4d1072c),在大多數其他呼叫中,我猜這是Python的gil同步。這個猜測有道理嗎?如果是這樣,那麼問題是為什麼等待需要1.4秒?是不是有人不釋放金邊?

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>

解決辦法

我已經設法在40多個執行緒顯示100%的“系統”CPU時間時從gdb獲得了一個執行緒轉儲。
以下是對每一個執行緒都相同的回溯:

#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

我最初的問題是把python和linux放在最前面和最中間,但問題似乎在於tbb和/或opencv。由於opencv和tbb被廣泛使用,我想它也必須以某種方式涉及到與我的特定環境的相互作用。可能是因為它是64核機器?
我在關閉tbb的情況下重新編譯了opencv,到目前為止問題還沒有再次出現。但我的應用程式現在執行速度變慢了。
我有posted this as a bug to OpenCV並將用來自該答案的任何內容更新此答案。