У меня есть параллельный код с использованием fork () для «чтения и преобразования изображений в градациях серого в двоичный файл».Я преобразовал код в многопоточный код, используя openmp.Но я заметил, что код openmp дает низкую производительность по сравнению с кодом, использующим fork.Сначала я подозревал, что это может быть openmp, и поэтому пытался напрямую использовать pthreads.Но я замечаю ту же картину.Время выполнения pthreaded-кода также выше по сравнению с разветвленным кодом (примечание: pthreads немного лучше, чем openmp, всего за несколько микросекунд)
Вот время выполнения при идентичных условиях.
+-----------------+-------------+--------------+
| No. of children | using fork | using openmp |
+-----------------+-------------+--------------+
| 20 | 1.3 | 1.6 |
| 50 | 1.6 | 2.2 |
| 100 | 2.7 | 3.7 |
| 150 | 3.7 | 5.3 |
| 200 | 4.5 | 7.1 |
| 250 | 6.0 | 9.0 |
| 600 | 15.2 | 22.06 |
+-----------------+-------------+--------------+
Редактировать: добавлен код.Компилятор: gcc-4.8.5, Количество процессоров: 256
функция вызывается следующими кодами:
void imgProcess(char* nam){
Pix *pixg = pixRead(nam);
Pix *pixb, *pixgray;
pixgray = pixConvertRGBToGray(pixg,0.33,0.33,0.34);
pixSauvolaBinarizeTiled(pixgray, 8, 0.34, 1, 1, NULL, &pixb);
pixDestroy(&pixg);
pixDestroy(&pixb);
}
Код с использованием fork ():
int main() {
char prefix[60]="/root/Test/img_";
struct timespec i1, i2;
long long elapsed;
clock_gettime(CLOCK_MONOTONIC, &i1);
int count = 200;
for(int i=0; i<count; i++){
if(fork() == 0){
char filname[60];
sprintf(filname,"%s%d%s",prefix,i,".jpg");
imgProcess(filname);
exit(0);
}
}
for(int i=0; i<count; i++)
wait(NULL);
clock_gettime(CLOCK_MONOTONIC, &i2);
elapsed = i2.tv_sec*1000000000LL + i2.tv_nsec - i1.tv_sec*1000000000LL - i1.tv_nsec;
cout<<"Total : "<<(double)elapsed/1000000000LL<<endl;
return 0;
}
Код с использованием openmp:
int main() {
int count = 200;
omp_set_num_threads(count);
char prefix[60]="/root/Test/img_";
struct timespec i1, i2;
long long elapsed;
clock_gettime(CLOCK_MONOTONIC, &i1);
#pragma omp parallel for
for(int j=0;j<count;j++){
char filname[60];
sprintf(filname,"%s%d%s",prefix,j,".jpg");
imgProcess(filname);
}
clock_gettime(CLOCK_MONOTONIC, &i2);
elapsed = i2.tv_sec*1000000000LL + i2.tv_nsec - i1.tv_sec*1000000000LL - i1.tv_nsec;
cout<<"Total : "<<(double)elapsed/1000000000LL<<endl;
return 0;
}
Даже если я признаю, что после некоторого числа forks () будет быстрее, чемпотоков, в соответствии с этим потоком , я все еще не думаю, что они будут быстрее на несколько секунд.
Дополнительная информация: Я провел два небольших теста.
- Первый тест: Вместо использования функции imgProcess (), указанной выше, в качестве единицы работы, теперь у меня есть простая «трата времени на цикл» в качестве единицы работы дляпараллельных заданий и заметил, что openmp и разветвленный код имеют почти одинаковые тайминги.
Второй тест: Вместо использования функции imgProcess () выше в качестве единицы работы, моя единица измеренияработа для параллельной работы - «чтение текстового файла» с использованием потока C ++.Времена для openmp-кода и разветвленного кода также схожи в этом случае.
+---------+-------+--------+
| threads | fork | openmp |
+---------+-------+--------+
| 20 | 0.018 | 0.008 |
| 50 | 0.04 | 0.01 |
| 100 | 0.08 | 0.04 |
| 150 | 0.11 | 0.03 |
| 200 | 0.16 | 0.07 |
| 250 | 0.19 | 0.08 |
+---------+-------+--------+
Вопросы:
- Я был подТакое впечатление, что потоки и вилки должны иметь одинаковое время выполнения.Есть идеи выяснить, почему многопоточный код ведет себя по-разному в разных случаях?
- До сих пор я просто заменял часть fork () на потоки.На самом деле есть область для распараллеливания самого алгоритма преобразования серого в двоичное изображение, чего я еще не сделал.Видя вышеприведенное время, я чувствую, что не стоит продолжать распараллеливание алгоритма.Что вы мне предлагаете?Считаете ли вы, что это может быть полезным для распараллеливания?