Проблема блокировки приложений Python/OpenCV
Приложение My Python, работающее на 64-ядерном Linux-сервере, обычно работает без проблем. Затем, после некоторого случайного промежутка времени (обычно от 0,5 до 1,5 дней), я внезапно начинаю частые паузы/блокировки более 10 секунд! Во время этих блокировок системное время процессора (т.е. Время в ядре) может быть более 90% (да: 90% всех 64 ядер, а не только одного процессора).
Мое приложение перезапускается часто в течение дня. Перезапуск приложения не устраняет проблему. Однако перезагрузка машины.
Вопрос 1. Что может привести к 90% времени системного процессора в течение 10 секунд? Все системное время процессора находится в моем родительском процессе Python, а не в дочерних процессах, созданных с помощью многопроцессорности Python или других процессов. Таким образом, это означает что-то порядка 60+ потоков, затрачивающих 10+ секунд в ядре. Я даже не уверен, что это проблема Python или проблема ядра Linux.
Вопрос 2: проблема с перезагрузкой проблемы должна быть большой подсказкой в отношении причины. Какие ресурсы Linux могут быть исчерпаны в системе между перезагрузкой приложения, но не между перезагрузками, которые могут заставить эту проблему застревать?
То, что я пробовал до сих пор, чтобы решить эту проблему/выяснить ее
Ниже я расскажу о многопроцессорной обработке. Это потому, что приложение работает в цикле, и многопроцессорность используется только в одной части цикла. Высокий ЦП почти всегда происходит сразу же после завершения всех вызовов многопроцессорности. Я не уверен, что это намек на причину или красную селедку.
- Мое приложение запускает поток, который использует
psutil
для вывода статистики процесса и системного процессора каждые 0,5 секунды. Я самостоятельно подтвердил, что он сообщает с помощью top
.
- Я конвертировал мое приложение из Python 2.7 в Python 3.4, потому что Python 3.2 получил новую реализацию GIL, а 3.4 перезаписал многопроцессорную обработку. Хотя это улучшило ситуацию, оно не решило проблему (см. мой предыдущий вопрос SO, который я ухожу, потому что это еще полезный ответ, если не общий ответ).
- Я заменил ОС. Первоначально это был Ubuntu 12 LTS, теперь это CentOS 7. Никакой разницы.
- Получается многопоточное и многопроцессорное столкновение в Python/Linux и не рекомендуется вместе, у Python 3.4 теперь есть
forkserver
и spawn
контексты многопроцессорности. Я пробовал их, никакой разницы.
- Я проверил /dev/shm, чтобы убедиться, что у меня закончилась общая память (которую использует Python 3.4 для управления многопроцессорной обработкой), ничего
-
lsof
вывод списка всех ресурсов здесь
- Трудно проверить на других машинах, потому что я запускаю многопроцессорный пул из 59 детей, и у меня нет других 64-х основных машин, которые просто лежат
- Я не могу запускать его с помощью потоков, а не процессов, потому что он просто не может работать достаточно быстро из-за GIL (следовательно, почему я переключился на многопроцессорность в первую очередь).
- Я попытался использовать
strace
только в одном потоке, который работает медленно (он не может работать во всех потоках, потому что он слишком сильно замедляет приложение). Ниже я получил то, что не говорит мне много.
-
ltrace
не работает, потому что вы не можете использовать -p
для идентификатора потока. Даже просто запустить его в основном потоке (нет -f
) делает приложение настолько медленным, что проблема не появляется.
- Проблема не связана с загрузкой. Иногда он будет работать нормально при полной нагрузке, а затем при половинной нагрузке он вдруг столкнется с этой проблемой.
- Даже если я перезагружаю компьютер каждую ночь, проблема возвращается каждые пару дней.
Среда/примечания:
- Python 3.4.3, скомпилированный из источника
- CentOS 7 полностью обновлен.
uname -a
: Linux 3.10.0-229.4.2.el7.x86_64 # 1 SMP Wed 13 мая 10:06:09 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux (хотя это обновление ядра было применено только сегодня)
- Машина имеет 128 ГБ памяти и имеет множество бесплатных
- Я использую numpy, связанный с ATLAS. Я знаю, что OpenBLAS сталкивается с многопроцессорностью Python, но ATLAS этого не делает, и это столкновение решается с помощью Python 3.4
forkserver
и spawn
, которые я пробовал.
- Я использую OpenCV, который также выполняет много параллельной работы.
- Я использую
ctypes
для доступа к библиотеке C.so, предоставленной производителем камеры.
- Приложение работает под управлением root (требование библиотеки C, на которую я ссылаюсь)
- Многопроцессорность Python
Pool
создается в коде, защищенном if __name__ == "__main__":
и в основном потоке
Обновлены результаты strace
Несколько раз мне удалось привязать поток, который работал на 100% "системном" процессоре. Но только однажды я получил от него что-то значимое. См. Ниже вызов в 10: 24: 12.446614, который занимает 1,4 секунды. Учитывая тот же идентификатор (0x7f05e4d1072c), который вы видите в большинстве других вызовов, я предполагаю, что это синхронизация PILON 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>
Ответы
Ответ 1
Мне удалось получить дамп потока из gdb
прямо в точке, где 40 + потоки показывают 100% -ное время процессора.
Здесь обратная трассировка, которая одинакова для каждого из этих потоков:
#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-ядерная машина?
Я перекомпилировал OpenCV с отключенным TBB, и проблема пока не появилась. Но теперь мое приложение работает медленнее.
Я разместил это как ошибку для OpenCV и обновит этот ответ всем, что от этого получится.