Я новичок в распараллеливании, и я надеюсь, что я не трачу впустую время. Я уже спросил несколько друзей, которые уже использовали openMP, но они не могли мне помочь. Поэтому я предположил, что мое дело может быть интересно и кому-то еще, по крайней мере, в образовательных целях, и я постарался документировать его настолько хорошо, насколько мог. Это два примера, один из которых на 100% взят из уроков Тима Мэттсона в youtube, другой каким-то образом упрощен, но, как мне кажется, все еще является стандартным подходом. В обоих случаях время вычисления масштабируется с количеством потоков за несколько итераций, но для очень большого количества итераций время вычисления, по-видимому, сходится к одному и тому же числу. Это, конечно, неправильно, так как я ожидаю, что время вычислений будет одинаковым для нескольких итераций и действительно оптимизировано для большого количества итераций.
Здесь два примера, оба скомпилированы с
g++ -fopenmp main.cpp -o out
Модель потока: posix
gcc версия 4.8.4 (Ubuntu 4.8.4-2ubuntu1 ~ 14.04), в Ubuntu 14.04
и со следующим заголовком:
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <iostream>
using namespace std;#define NUMBER_OF_THREADS 2
static long num_steps = 1000000000;
Теперь число ядер на компьютере, над которым я сейчас работаю, равно 8 (intel i7), поэтому любое количество потоков от 2 до 4, которое я ожидал, принесло бы некоторое большое преимущество с точки зрения времени вычислений.
Пример 1:
int main() {
omp_set_num_threads(NUMBER_OF_THREADS);
double step = 1.0/(double) num_steps, pi=0.0;
auto begin = chrono::high_resolution_clock::now();
#pragma omp parallel
{
int i, ID, nthrds;
double x, sum = 0;
ID = omp_get_thread_num();
nthrds = omp_get_num_threads();
for (i=ID; i<num_steps; i=i+nthrds) {
x = (i+0.5)*step;
sum = sum + 4.0/(1.0+x*x);
}
#pragma omp critical
pi += step*sum;
}
auto end = chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::nanoseconds>(end-begin).count()/1e6 << "ms\n";
return 0;
}
Пример 2:
int main() {
omp_set_num_threads(NUMBER_OF_THREADS);
double pi=0, sum = 0;
const double step = 1.0/(double) num_steps;
auto begin = chrono::high_resolution_clock::now();
// #pragma omp parallel
{
#pragma omp parallel for reduction(+:sum)
for (int i=0; i<num_steps; i++) {
double x = (i+0.5)*step;
sum += 4.0/(1.0+x*x);
}
}
pi += step*sum;
auto end = std::chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::nanoseconds>(end-begin).count()/1e6 << "ms\n";
return 0;
}
Вначале я думал, что пример 2 замедляется сокращением переменной, что мешает распараллеливанию, но в примере 1 почти ничего не поделено. Дайте мне знать, если я делаю что-то действительно глупое, или я могу указать больше аспектов проблемы. Спасибо всем.
Как отметил Жиль в комментариях, проблема заключалась в том, что я измерял время с помощью clock (), который суммирует все тики ядер.
с
chrono::high_resolution_clock::now();
я получаю ожидаемое ускорение.
для меня вопрос прояснен, но, может быть, мы можем оставить это в качестве примера для будущих нубов, таких как я, для ссылки. Если какой-то мод верит в другое, пост может быть удален.
Спасибо еще раз за помощь
Других решений пока нет …