Я пытаюсь распараллелить код, который выполняется много раз (и, следовательно, счетчик миллисекунд).Я хотел бы использовать многопоточность C ++ 11, так как она может работать в Mac OS X без необходимости требовать от пользователя установки OpenMP (например, с помощью Homebrew).Однако я считаю, что производительность OpenMP значительно лучше, чем многопоточность C ++ 11.
Удивительно, но даже когда C ++ 11 использует только один поток, он имеет значительно больше накладных расходов, чем OpenMP.Для приведенного ниже простого цикла у нас есть следующие времена (используя только один поток):
C++11 Multithreading: 57 ms
OpenMP Multithreading: 47 ms
Native for loop: 43 ms
Я вижу более существенные улучшения в скорости для потоков OpenMP по сравнению с C ++ 11 при использовании более 1 потока.Как я могу получить скорости OpenMP-типа с многопоточностью C ++ 11?
Вот некоторый адаптированный код, который более или менее выполняет то, что пытается сделать мой настоящий код.
C++ 11 Многопоточность
#include <stdlib.h>
#include <stdio.h>
#include <thread>
#include <vector>
#include <algorithm>
#include <time.h>
long int diff(timespec start, timespec end)
{
long int tv_nsec;
tv_nsec = 1000000000*(end.tv_sec-start.tv_sec)+end.tv_nsec-start.tv_nsec;
return tv_nsec;
}
int main() {
int n = 1E6;
int ndim = 3;
int nthreads = 1;
double * arr1 =(double*) malloc(n* sizeof(double));
double * arr2 =(double*) malloc(n* sizeof(double));
double * xs=(double*) malloc(n* sizeof(double));
double * ys =(double*) malloc(n* sizeof(double));
int * iarr =(int*) malloc(n* sizeof(int));
double * arr3 =(double*) malloc(n*ndim *sizeof(double));
for (int i = 0; i++ ; i<n) {
iarr[i] = i;
xs[i] = i;
ys[i] = i; for (int j = 0; j++ ; j<ndim) {
charges[j*ndim +i] = i*j;
}
}
struct timespec start10,start20, end10, end20;
clock_gettime(CLOCK_MONOTONIC, &start10);
{
std::vector<std::thread> threads(nthreads);
for (int t = 0; t < nthreads; t++) {
threads[t] = std::thread(std::bind(
[&](const int bi, const int ei, const int t)
{
for(int i = bi;i<ei;i++)
{
{
arr1[i] = xs[iarr[i]];
arr2[i] = ys[iarr[i]];
for (int idim=0; idim<ndim; idim++){
arr3[idim*n+i] = charges[idim*n +iarr[i]];
}
}
}
},t*n/nthreads,(t+1)==nthreads?n:(t+1)*n/nthreads,t));
}
std::for_each(threads.begin(),threads.end(),[](std::thread& x){x.join();});
}
clock_gettime(CLOCK_MONOTONIC, &end10);
printf("Initializing and sorting (%d threads): %.2lf ms\n",nthreads, (diff(start10,end10))/(double)1E6);
OpenMP:
struct timespec start10,start20, end10, end20;
clock_gettime(CLOCK_MONOTONIC, &start10);
#pragma omp parallel num_threads(1)
{
#pragma omp for
for (int i = 0; i<n; i++){
arr1[i] = xs[iarr[i]];
arr2[i] = ys[iarr[i]];
for (int idim=0; idim<ndim; idim++){
arr3[idim*n+i] = charges[idim*n +iarr[i]];
}
}
}
clock_gettime(CLOCK_MONOTONIC, &end10);
printf("Initializing and sorting (%d threads): %.2lf ms\n",nthreads, (diff(start10,end10))/(double)1E6);
}