Я хотел бы узнать OpenMP немного, потому что я хотел бы иметь огромный цикл, параллельный. После некоторого чтения (SO, Common OMP mistakes, tutorial и т. Д.), Я принял в качестве первого шага в основном рабочий код c/mex, приведенный ниже (который дает разные результаты для первого тестового примера).Что следует учитывать при чтении массива из нескольких потоков?
- Первый тест делает суммировать значение результата - функции
serial, parallel
-, - вторые принимают значения из входного массива и записывают обработанные значения выходного массива - функции
serial_a, parallel_a
.
Мои вопросы:
- Почему отличаются результаты первого теста, т.е.. е. результаты
serial
иparallel
- Удовлетворительно второе испытание выполнено успешно. Я беспокоюсь о том, как обрабатывать память (расположения массива), которые, возможно, читаются несколькими потоками? ? В примере это должно быть эмулировано
a[i])/cos(a[n-i]
. - Есть несколько простых правил, как определить, какие переменные объявлять частного, совместно и сокращения?
- В обоих случаях
int i
находится за пределамиpragma
, однако второй тест дает правильные результаты. Так или иначе, илиi
необходимо переместить в областьpragma omp parallel
, as being said here? - Любые другие намеки на выявленные ошибки?
Код
#include "mex.h"
#include <math.h>
#include <omp.h>
#include <time.h>
double serial(int x)
{
double sum=0;
int i;
for(i = 0; i<x; i++){
sum += sin(x*i)/cos(x*i+1.0);
}
return sum;
}
double parallel(int x)
{
double sum=0;
int i;
#pragma omp parallel num_threads(6) shared(sum) //default(none)
{
//printf(" I'm thread no. %d\n", omp_get_thread_num());
#pragma omp for private(i, x) reduction(+: sum)
for(i = 0; i<x; i++){
sum += sin(x*i)/cos(x*i+1.0);
}
}
return sum;
}
void serial_a(double* a, int n, double* y2)
{
int i;
for(i = 0; i<n; i++){
y2[i] = sin(a[i])/cos(a[n-i]+1.0);
}
}
void parallel_a(double* a, int n, double* y2)
{
int i;
#pragma omp parallel num_threads(6)
{
#pragma omp for private(i)
for(i = 0; i<n; i++){
y2[i] = sin(a[i])/cos(a[n-i]+1.0);
}
}
}
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
double sum, *y1, *y2, *a, s, p;
int x, n, *d;
/* Check for proper number of arguments. */
if(nrhs!=2) {
mexErrMsgTxt("Two inputs required.");
} else if(nlhs>2) {
mexErrMsgTxt("Too many output arguments.");
}
/* Get pointer to first input */
x = (int)mxGetScalar(prhs[0]);
/* Get pointer to second input */
a = mxGetPr(prhs[1]);
d = (int*)mxGetDimensions(prhs[1]);
n = (int)d[1]; // row vector
/* Create space for output */
plhs[0] = mxCreateDoubleMatrix(2,1, mxREAL);
plhs[1] = mxCreateDoubleMatrix(n,2, mxREAL);
/* Get pointer to output array */
y1 = mxGetPr(plhs[0]);
y2 = mxGetPr(plhs[1]);
{ /* Do the calculation */
clock_t tic = clock();
y1[0] = serial(x);
s = (double) clock()-tic;
printf("serial....: %.0f ms\n", s);
mexEvalString("drawnow");
tic = clock();
y1[1] = parallel(x);
p = (double) clock()-tic;
printf("parallel..: %.0f ms\n", p);
printf("ratio.....: %.2f \n", p/s);
mexEvalString("drawnow");
tic = clock();
serial_a(a, n, y2);
s = (double) clock()-tic;
printf("serial_a..: %.0f ms\n", s);
mexEvalString("drawnow");
tic = clock();
parallel_a(a, n, &y2[n]);
p = (double) clock()-tic;
printf("parallel_a: %.0f ms\n", p);
printf("ratio.....: %.2f \n", p/s);
}
}
Выход
>> mex omp1.c
>> [a, b] = omp1(1e8, 1:1e8);
serial....: 13399 ms
parallel..: 2810 ms
ratio.....: 0.21
serial_a..: 12840 ms
parallel_a: 2740 ms
ratio.....: 0.21
>> a(1) == a(2)
ans =
0
>> all(b(:,1) == b(:,2))
ans =
1
Система
MATLAB Version: 8.0.0.783 (R2012b)
Operating System: Microsoft Windows 7 Version 6.1 (Build 7601: Service Pack 1)
Microsoft Visual Studio 2005 Version 8.0.50727.867
* если каждая итерация параллельного цикла работает на другом элементе массива, вам не нужно беспокоиться об общих и частных * хорошо. Но что, если одни и те же элементы массива должны быть прочитаны разными потоками? ОМП позаботится об этом, например. г. нить просто ждет, если элементы читаются другим? Или читающий доступ не проблема вообще? А как насчет случая, что элементы, возможно, должны быть изменены разными потоками? Возможно ли это вообще? – embert
Если одни и те же элементы массива должны быть прочитаны разными потоками, вам не нужно беспокоиться об этом. Каждый поток будет извлекать данные в локальный кеш. Однако вам придется беспокоиться, если более одного потока будет писать один и тот же элемент массива. Это может привести к условиям гонки. У вас также могут возникать проблемы с написанием элементов, которые не являются одинаковыми, но локальными. Это называется ложным совместным использованием. –