Справочная информация:
Я прочитал несколько статей и сообщений, касающихся многопоточности в OpenCV:
- С одной стороны, вы можете создавать OpenCV с поддержкой TBB или OpenMP, которые распараллеливают функции OpenCV внутри.
- С другой стороны, вы можете создавать несколько потоков самостоятельно и вызывать параллельные функции для реализации многопоточности на уровне приложений.
Но я не мог получить последовательные ответы, какой метод многопоточности - правильный путь.
Что касается TBB, ответ answer 2012 года с 5 ответами:
С WITH_TBB = ON OpenCV пытается использовать несколько потоков для некоторых функций. Проблема в том, что на данный момент только TBF имеет много функций (может быть дюжина). Так что трудно увидеть какое-либо ускорение. Философия OpenCV заключается в том, что приложение должно быть многопоточным, а не функциями OpenCV. [...]
Что касается многопоточности на уровне приложения, комментарий от модератора на answers.opencv.org:
пожалуйста, избегайте использования своей собственной многопоточности с opencv. многие функции явно не поточнобезопасны. скорее перестройте библиотеки opencv с поддержкой TBB или openmp.
Но другой ответ с 3 ответами гласит:
Сама библиотека является поточно-ориентированной, поскольку вы можете одновременно выполнять несколько вызовов в библиотеку, однако данные не всегда являются поточно-ориентированными.
Описание проблемы:
Поэтому я подумал, что по крайней мере можно использовать многопоточность на уровне приложений. Но я столкнулся со странными проблемами с производительностью при запуске моей программы в течение более длительных периодов времени.
После изучения этих проблем с производительностью я создал этот минимальный, полный и проверяемый пример кода:
#include "opencv2\opencv.hpp"
#include <vector>
#include <chrono>
#include <thread>
using namespace cv;
using namespace std;
using namespace std::chrono;
void blurSlowdown(void*) {
Mat m1(360, 640, CV_8UC3);
Mat m2(360, 640, CV_8UC3);
medianBlur(m1, m2, 3);
}
int main()
{
for (;;) {
high_resolution_clock::time_point start = high_resolution_clock::now();
for (int k = 0; k < 100; k++) {
thread t(blurSlowdown, nullptr);
t.join(); //INTENTIONALLY PUT HERE READ PROBLEM DESCRIPTION
}
high_resolution_clock::time_point end = high_resolution_clock::now();
cout << duration_cast<microseconds>(end - start).count() << endl;
}
}
Фактическое поведение:
Если программа работает в течение длительного периода времени, промежуток времени, напечатанный
cout << duration_cast<microseconds>(end - start).count() << endl;
становится все больше и больше.
После запуска программы в течение примерно 10 минут время печати увеличилось вдвое, что невозможно объяснить обычными колебаниями.
Ожидаемое поведение:
Поведение программы, которое я ожидаю, состоит в том, что промежутки времени остаются почти постоянными, даже если они могут быть дольше, чем непосредственный вызов функции.
Примечания:
При непосредственном вызове функции:
[...]
for (int k = 0; k < 100; k++) {
blurSlowdown(nullptr);
}
[...]
Печатные промежутки времени остаются постоянными.
Когда не вызывается функция cv:
void blurSlowdown(void*) {
Mat m1(360, 640, CV_8UC3);
Mat m2(360, 640, CV_8UC3);
//medianBlur(m1, m2, 3);
}
Печатные промежутки времени также остаются постоянными. Поэтому при использовании потоков в сочетании с функциями OpenCV должно быть что-то не так.
- Я знаю, что приведенный выше код НЕ достигает фактической многопоточности, в то же время будет активен только один поток, вызывающий функцию
blurSlowdown()
. - Я знаю, что создание потоков и их очистка после этого не будут бесплатными и будут медленнее, чем прямой вызов функции.
- НЕ о том, что код вообще медленный. Проблема в том, что напечатанные промежутки времени становятся все длиннее и длиннее.
- Эта проблема не связана с функцией
medianBlur()
, поскольку она возникает в других функциях, например,erode()
илиblur()
. - Проблема была воспроизведена под Mac под clang++, см. комментарий @Mark Setchell
- Проблема усиливается при использовании библиотеки отладки вместо выпуска
Моя среда тестирования:
- Windows 10 64bit
- Компилятор MSVC
- Официальные двоичные файлы OpenCV 3.4.2
Мои вопросы:
- Можно ли использовать (мульти) многопоточность на уровне приложений с OpenCV?
- Если да, почему промежутки времени, напечатанные моей программой, выше РОСТА с течением времени?
- Если нет, почему OpenCV тогда считается потокобезопасным, и, пожалуйста, объясните, как вместо этого интерпретировать выражение Кирилла Корнякова instead
- Широко ли поддерживается TBB/OpenMP в 2019 году?
- Если да, что предлагает лучшую производительность, многопоточность на уровне приложений (если разрешено) или TBB/OpenMP?