Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[34.203.242.200] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Пытаюсь научиться многоядерному программированию. Начал с OpenMP. Нашел пример подсчета суммы элементов массива. Сравнил обычную функцию и функцию с использованием OpenMP, оказалось, что наибольший эффект от использования OpenMP достигается тогда, когда в инструкции
#pragma omp parallel shared(a) reduction (+: sum) num_threads(4) 1. С помощью каких функций API можно определить количество логических процессоров? 2. На ПК с другим количеством логических процессоров нужно указывать другое число. Можно ли в директиве #pragma менять это число или нужно после определения количества логических процессоров делать switch на возможные значения и устанавливать в директиве pragma количество процессоров в ветвях switch? |
Сообщ.
#2
,
|
|
|
Посмотри
omp_get_max_threads omp_set_num_threads |
Сообщ.
#3
,
|
|
|
Спасибо за подсказку. omp_get_max_threads()=4 на моем ПК, т.е. равно числу логических процессоров. Но если сделать так:
omp_set_num_threads(16); cout << "Максимальное количество потoков: " << omp_get_max_threads() << endl; |
Сообщ.
#4
,
|
|
|
Сообщ.
#5
,
|
|
|
omp_get_num_procs() дает 4, наверное это лучшее решение
|
Сообщ.
#6
,
|
|
|
А по второму вопросу? В прагме нельзя менять число, нужно использовать switch после определения числа логических процессоров?
|
Сообщ.
#7
,
|
|
|
Цитата tuchin @ А по второму вопросу? В прагме нельзя менять число, нужно использовать switch после определения числа логических процессоров? #pragma - это compile-time. Тебе же нужен runtime Просто вызови эти функции перед прагмой. Что-то типа omp_set_num_threads(omp_get_num_procs()) #pragma omp parallel |
Сообщ.
#8
,
|
|
|
Спасибо, понятно
Добавлено Хотел бы еще спросить о том, как правильно определять выигрыш при использовании OpenMP. В программе #include <string> #include <iostream> #include <Windows.h> #include <memory.h> #include <stdio.h> #include <time.h> #include <omp.h> using namespace std; double sum_arr(double* a, const long long n) // обычная функция { double sum = 0.0; for(int i = 0; i < n; ++i) { sum += a[i]; } return sum; } double sum_arr_openmp(double* a, const long long n) { double sum = 0.0; omp_set_num_threads(omp_get_num_procs()); #pragma omp parallel shared(a) reduction (+: sum) { #pragma omp for for (long long i = 0; i < n; ++i) { sum += a[i]; } } return sum; } int main() { setlocale(LC_ALL, ""); clock_t start, finish; omp_set_num_threads(16); cout << "Максимальное количество threads: " << omp_get_max_threads() << endl; cout << "Количество procs: " << omp_get_num_procs() << endl; long long n = 100000000; double* a = (double*)malloc(sizeof(double)*n); for(long long i = 0; i < n; ++i) { a[i] = i; } start = clock(); double sum = sum_arr(a, n); finish = clock(); double duration = (double)(finish - start); cout << "Сумма = " << sum << ". Время расчета без OpenMP = " << duration << endl; start = clock(); sum = sum_arr_openmp(a, n); finish = clock(); duration = (double)(finish - start); cout << "Сумма = " << sum << ". Время расчета c OpenMP = " << duration << endl; free(a); system("\npause"); } |
Сообщ.
#9
,
|
|
|
запускайте несколько сотен раз подряд и усредняйте результат
|
Сообщ.
#10
,
|
|
|
Цитата tuchin @ все время при каждом запуске получаются разные результаты Разные, это какие? Что именно там не так? Кстати, а почему ты пользуешися именно omp, а не обычными потоками? |
Сообщ.
#11
,
|
|
|
Вообще, я бы для начала убедился, что цикл, который у тебя выполняется в sum_arr_openmp выполняется параллельно, берёт нужный диапазон, и ничего лишний раз не блокирует.
Я нифига не понимаю в omp, но в этой задаче сделал бы, чтоб каждый поток считал свою сумму, а потом, по выходу из цикла, прибавлял её к общей. Здесь же выглядит так, что есть общая переменная sum, которая блокируется каждым потоком, в каждой итерации. В этом случае результат далеко не однозначен. |
Сообщ.
#12
,
|
|
|
Цитата tuchin @ все время при каждом запуске получаются разные результаты Ну естественно разные, у тебя классическая гонка потоков (race condition на буржуйском). |
Сообщ.
#13
,
|
|
|
А как это исправить?
Добавлено Цитата Олег М @ Разные, это какие? Что именно там не так? Кстати, а почему ты пользуешися именно omp, а не обычными потоками? Потому что многопоточным программированием никогда не занимался, решил, что профессионалы (которые создали OpenMP, OpenCL, C++ AMP) лучше справятся с задачей создания многопоточного программирования, чем новичок. |
Сообщ.
#14
,
|
|
|
Цитата tuchin @ Ну у меня получилось просто "тупым" более аккуратным распараллеливанием:А как это исправить? double sum_arr_openmp2(double *a, const long long n) { double sum = 0.0; int k; omp_set_num_threads( k = omp_get_num_procs()); #pragma omp parallel for shared(a,k) reduction (+: sum) for( int p=0; p<k; p++) { double sumP=0.0;// omp_get_thread_num() long long stopP = (p+1)*n/k; for( long long i = p*n/k; i < stopP; i++) sumP += a[i]; sum += sumP; } return sum; } А вот на x86 увы: 777 153 175 |
Сообщ.
#15
,
|
|
|
Цитата tuchin @ А как это исправить? Убедиться, что два потока никогда не смогут одновременно менять одну и ту же переменную. Использовать либо атомарный инкремент, либо критические секции для этого. |