Я хотел бы знать прогресс цикла for с использованием OpenMP.
Я знаю, что директива сокращения не работает, но я написал так:
#pragma omp for reduction (+:sum)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
sum++;
#pragma omp critical
cout << sum << " / " << size << endl;
}
это вернет что-то вроде этого:
1 / 100
1 / 100
2 / 100
1 / 100
...
но я хочу этого:
1 / 100
2 / 100
3 / 100
. ..
Есть ли способ получить правильный sum
значение во время reduction
Директива?
или я должен использовать другой метод?
reduction
пункт имеет очень четко определенное значение, подробно объясненное в разделе 2.9.3.6 новейший стандарт OpenMP. Я сомневаюсь, что вы сможете использовать его для целей, описанных выше.
В любом случае, возможно реализовать это поведение с небольшими изменениями в вашем источнике:
sum = 0
#pragma omp for shared(sum) schedule(guided)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
#pragma omp critical(PRINT)
{
sum++;
cout << sum << " / " << size << endl;
}
}
Таким образом, вы можете быть уверены, что только один поток пытается увеличить сумму и вывести ее на экран. Учитывая длительность каждой итерации, такая синхронизация не должна вызывать проблем с производительностью.
Вы должны использовать другой метод. Редукция создает приватную переменную потока (в вашем случае sum
), которое уменьшается только в конце, когда все потоки объединяются. Сокращение сильно зависит от реализации. Он может ожидать завершения всех потоков, может уменьшаться по завершении потоков, может создавать дерево сокращений и т. Д.
Вместо этого, чтобы отслеживать прогресс, вы могли бы иметь другую переменную numDone
, который каждый поток атомарно увеличивается.
РЕДАКТИРОВАТЬ
Википедия объясняет это довольно хорошо:
сокращение (оператор | встроенный: список): переменная имеет локальную копию
в каждом потоке, но значения локальных копий будут суммироваться
(уменьшено) в глобальную переменную общего доступа.
Чтобы избежать необходимости обмена данными (от обновления общего счетчика), вы можете просто распечатать номер потока вместе с количеством элементов, которые он обработал до настоящего времени, т.е.
#pragma omp parallel
{
int count = 0;
#pragma omp for schedule(dynamic) // or whatever schedule you want
for(int i=0; i<size; ++i) {
// ...
printf("@ %d: done %d loops\n",
omp_get_thread_num(),++count); // should not need a critical section
}
}
В вашем конкретном случае, поскольку работа занимает около 10 секунд, любые коммуникации не являются критическими, но может быть целесообразно использовать динамическое расписание, в частности, если работа может варьироваться между различными i
,