Подскажите как искать лажу в проге
Для ускорения работы решила распараллелить по нитям и тут результаты стали получаться другие.
При этом если из приложения-интерфейса, в которое подключен модуль с нитями пошагово зайти внутрь библиотеки достаточно глубоко, то получаются результаты как и в последовательной библиотеке.
Вот 2 варианта кода:
Последовательный:
classifiers[numcl]->loadSample(d);
classifiers[numcl]->classifyProb();
resultProb[numcl] = classifiers[numcl]->getOutputValue();
}
Параллельный:
for (unsigned numcl = 0; numcl < classifiers.size(); numcl++) {
ThreadParamsProcessor *prms = new ThreadParamsProcessor;
prms->cl = classifiers[numcl];
prms->d = &d;
prms->multiplier = &(resultProb[numcl]);
CWinThread *pThread = ::AfxBeginThread(ThreadProcessImppr, prms);
threadHandles[numcl] = pThread->m_hThread;
}
::WaitForMultipleObjects(classifiers.size(), threadHandles, TRUE, INFINITE);
Среда VS2008
Подскажите, где искать и что искать...
Хотя может все и не от этого. Я такой вывод сделала когда стала выводить внутреннии параметры классификаторов, а печать пошла уже после того, как напечателся конечный резуль, а ее ответ уже ушел...
На самом деле ничего и не умным даже, зачем создаю ссылки на нити внутри цикла, они при переходе к следующей итерации успешно удаляются и жать становится нечего и неотчего, поэтому и не работало.
Вот пример работающего кода с нитями:
vector <HANDLE> hThreads;
objThreads.reserve(classifiers.size());
hThreads.reserve(classifiers.size());
for (int numcl = 0; numcl < (int)classifiers.size(); numcl++) {
ThreadParamsProcessor *prms = new ThreadParamsProcessor;
prms->cl = classifiers[numcl];
prms->d = &d;
prms->multiplier = &(resultProb[numcl]);
objThreads.push_back(AfxBeginThread(ThreadProcessImppr, prms, THREAD_PRIORITY_NORMAL, NULL, CREATE_SUSPENDED));
objThreads[numcl]->m_bAutoDelete = FALSE;
objThreads[numcl]->ResumeThread();
hThreads.push_back(objThreads[numcl]->m_hThread);
}
::WaitForMultipleObjects(hThreads.size(), &hThreads[0], TRUE, INFINITE);
Только теперь это работает не бустрее последовательного варианта, а даже чуть медленее (~10 мс), а ожидалось ускорение, хотя бы в 2 раза....
В проектах везде установлено, что они должны быть многопоточные
Сделала то же самое с использованием средств openmp, стало еще медленее...
Код, который я привожу находится как раз внутри библиотеки.
Может будет полезным:
Время обработки всеми классификаторами (6 штук) на самом деле получается (те, что в коде называются classifiers) порядка 170-200 мс. Среди них есть 2 медленных и 4 быстрых, быстрые работают за 0.05 мс, а вот все остальное время занимают медленные.
Код, который я привожу находится как раз внутри библиотеки.
А код действительно выполняется параллельно?
Нет ли в библиотеке каких-то общих данных, обращение к которым требует синхронизации (и она происходит с эффектом - все потоки выполняются по очереди, без выигрыша в производительности)?
Приведу код самой нити:
float *multiplier;
IClassifier *cl;
const DBSampleData *d;
};
UINT ThreadProcessImppr(LPVOID pParam) {
ThreadParamsProcessor *prm = (ThreadParamsProcessor*)pParam;
prm->cl->loadSample(*(prm->d));
prm->cl->classifyProb();
*(prm->multiplier) = prm->cl->getOutputValue();
delete prm;
return 0;
}
Классификаторы все свои внутренние данные содержат отдельно внутри, каждая нить работает со свои классификатором.
Есть только идея, что картинка, содержащаяся в d (DBSampleData) может не обрабатываться параллельно, но вообще-то ко всем данным в d обращаюсь только для чтения.
Есть только идея, что картинка, содержащаяся в d (DBSampleData) может не обрабатываться параллельно, но вообще-то ко всем данным в d обращаюсь только для чтения.
Идем дальше. Что за изображение?
float *dpca;
float *eigenf;
float *gabor;
char *picFileName;
IImagePreprocessor *imppr; // - это то самое изображение, точнее его обертка
float *pc2a;
float *pca;
};
Оберткуа изображения к проекту также подключается в виде библиотеки (lib), она тоже самописная, многопоточность поддерживает.
Внутри обертки обрабатываемое изображение содержится в виде OpenCV - IplImage*.
Раньше, вроде параллелила куски кода с OpenCV, проблем не было ускорение достигалось.
Кстати, примерное время работы - 200мс - это уже достаточно короткий промежуток времени при обработке одного изображения. Вообще запуск потока сама по себе небыстрая операция, потому вы возможно просто не замечаете ускорения. А вот OpenCV мог работать с уже изготовленными потоками, например из собственного пула.
Кстати, примерное время работы - 200мс - это уже сам по себе достаточно короткий промежуток времени при обработке одного изображения. Вообще запуск потока сама по себе небыстрая операция, потому вы возможно просто не замечаете ускорения. А вот OpenCV мог работать с уже изготовленными потоками, например из собственного пула.
Да на самом деле то, что я распараллеливала раньше - были более массивные куски кода, я написала это в качестве аргумента, что OpenCv должен нормально работать с нитями.
Может и вправду тут уже за счет нитей не получится ускориться...
Вы обрабатываете одно изображение или множество?
Если множество, то имеет смысл сделать рабочие потоки которым отдавать эти изображения, каждое из которых будет проходить в своем потоке последовательно через классификаторы.
Я думаю тогда ваш дизайн распараллеливания нужно пересмотреть. Незачем для каждого изображения при каждом запросе порождать 6 потоков. Заранее создайте набор из нужного количества потоков и передавайте им данные. Для синхронизации вам потребуется евент (для единомоментного запуска обработки данных в потоках) и семафор - для ожидания о завершения обработки данных.
Другим способом может быть использование пула потоков, предоставляемого системой (он будет походить на то что у вас сейчас).