Программа Pthread занимает больше времени, чем ожидалось

Привет,

Я создал многопоточное приложение для умножения двух матриц с помощью pthreads, но, к моему удивлению, многопоточная программа занимает больше времени, чем я ожидал.

Я не знаю, где проблема в моем коде, фрагмент кода приведен ниже:

#include "pthreads.h"
#include "cv.h"
#include "cxcore.h"

CvMat * matA;       /* first matrix */
CvMat * matB;       /* second matrix */
CvMat * matRes;     /* result matrix */

int size_x_a; /* this variable will be used for the first  dimension */
int size_y_a; /* this variable will be used for the second dimension */

int size_x_b,size_y_b;
int size_x_res;
int size_y_res;

struct v {
  int i; /* row */
  int j; /* column */
};


void *printThreadID(void *threadid)
{
/*long id = (long) threadid;
//printf("Thread ID: %ld\n", id);

arrZ[id] = arrX[id] + arrY[id];

pthread_exit(NULL);*/
return 0;
}

int main()
{
/* assigining the values of sizes */
size_x_a = 200;
size_y_a = 200;
size_x_b = 200;
size_y_b = 200;

/* resultant matrix dimensions */
size_x_res = size_x_a;
size_y_res = size_y_b;

matA = cvCreateMat(size_x_a,size_y_a,CV_64FC1);
matB = cvCreateMat(size_x_b,size_y_b,CV_64FC1);
matRes = cvCreateMat(size_x_res,size_y_res,CV_64FC1);

pthread_t thread1;
pthread_t thread2;
pthread_t multThread[200][200];

int res1;
int res2;
int mulRes;
/*******************************************************************************/ 

/*Creating a thread*/
res1 = pthread_create(&thread1,NULL,initializeA,(void*)matA);
if(res1!=0)
{
    perror("thread creation of thread1 failed");
    exit(EXIT_FAILURE);
}


/*Creating a thread*/
res2 = pthread_create(&thread2,NULL,initializeB,(void*)matB);

if(res2!=0)
{
    perror("thread creation of thread2 failed");
    exit(EXIT_FAILURE);
}


pthread_join(thread1,NULL);
pthread_join(thread2,NULL);

/*Multiplication of matrices*/
for(int i=0;i<size_x_a;i++)
    {
  for(int j=0;j<size_y_b;j++)
      {
      struct v * data = (struct v*)malloc(sizeof(struct v));
      data->i = i;
      data->j = j;

mulRes = pthread_create(&multThread[i][j],NULL,multiplication,  (void*)data);
       }
    }

for(int i=0;i<size_x_a;i++)
{
for(int j=0;j<size_y_b;j++)
    {
    pthread_join(multThread[i][j],NULL);    
    }
}


for(int i =0;i<size_x_a;i++)
{
    for(int j = 0;j<size_y_a;j++)
    {
        printf("%f ",cvmGet(matA,i,j));
    }
}
return 0;
}

void * multiplication(void * param)
{
struct v * data = (struct v *)param;
double sum =0;
for(int k=0;k<size_x_a;k++)
    sum += cvmGet(matA,data->i,k) * cvmGet(matB,k,data->j); 

cvmSet(matRes,data->i,data->j,sum);
pthread_exit(0);

return 0;
}

void * initializeA(void * arg)
{
CvMat * matA  = (CvMat*)arg;
//matA = (CvMat*)malloc(size_x_a * sizeof(CvMat *));

/*initialiazing random values*/
for (int i = 0; i < size_x_a; i++) 
{
 for (int j = 0; j < size_y_a; j++) 
 {
    cvmSet(matA,i,j,size_y_a + j); /* just some unique number for each element */
 }
}
return 0;
}

void * initializeB(void * arg)
{
CvMat* matB  = (CvMat*)arg;
//matB = (CvMat*)malloc(size_x_b * sizeof(CvMat *));

/*initialiazing random values*/
for (int i = 0; i < size_x_b; i++) 
{
  for (int j = 0; j < size_y_b; j++) 
  {
    cvmSet(matB,i,j,size_y_b + j); /* just some unique number for each element */
  }
}
return 0;
}

void * initializeRes(void * arg)
{
CvMat * res  = (CvMat*)arg;
//res = (CvMat*)malloc(size_x_res * sizeof(CvMat *));

/* for matrix matRes, allocate storage for an array of ints */
for (int i = 0; i < size_x_res; i++) 
{
    for (int j = 0; j < size_y_res; j++) 
    {
        cvmSet(matRes,i,j,0);
    }
}
return 0;
}

Я делаю эту многопоточность в первый раз. Пожалуйста, помогите мне с этим, любое предложение или исправление будет очень полезно.

Заранее спасибо.


person ATG    schedule 10.07.2012    source источник


Ответы (1)


Вы создаете МНОГО потоков, которые будут включать множество переключений контекста. Если каждый поток выполняет чистые вычисления и не будет включать какое-либо ожидание (например, сеть, сокеты и т. д.), нет причин, по которым многопоточность будет быстрее, чем без многопоточности. Если, конечно, вы не используете многопроцессорную/ядерную машину, вам следует создать по одному потоку на ядро. При такой обработке большее количество потоков, чем ядер, просто замедляет ее.

Что вы можете сделать, так это разделить рабочий набор на задачи, которые можно ставить в очередь, и иметь рабочие потоки (одно ядро ​​на ЦП), которые будут вытягивать задачи из общей рабочей очереди. Это стандартная проблема производителя/потребителя.

Здесь представлена ​​некоторая общая информация о проблеме производителя/потребителя.

Прошло много времени с тех пор, как я занимался умножением матриц, так что терпите меня :) Похоже, вы могли бы разделить следующие задачи на отдельные задачи:

/*Multiplication of matrices*/
for(int i=0;i<size_x_a;i++)
    {
  for(int j=0;j<size_y_b;j++)
      {
      struct v * data = (struct v*)malloc(sizeof(struct v));
      data->i = i;
      data->j = j;

      /* Instead of creating a thread, create a task and put it on the queue
       * mulRes = pthread_create(&multThread[i][j],NULL,multiplication,  (void*)data);
       */

      /* Im not going to implement the queue here, since there are several available
       * But remember that the queue access MUST be mutex protected. */
      enqueue_task(data);
       }
    }

Ранее вам нужно будет создать так называемый пул потоков (рабочие потоки, по одному на ядро ​​ЦП), чья рабочая функция будет пытаться вытащить очередь и выполнить работу. Есть способы сделать это с помощью условных переменных pthread, в результате чего потоки блокируются/ожидают переменную условия, если очередь пуста, и как только очередь заполняется, переменная состояния сигнализируется, тем самым освобождая потоки, чтобы они могли начать работающий.

Если это не логическое разделение работы, и вы не можете его найти, то, возможно, эта проблема не подходит для многопоточности.

person Brady    schedule 10.07.2012
comment
спасибо за ответ, это то, что я не понимаю, как использовать меньше потоков для этого расчета. У меня есть процессор с 4 ядрами, что означает, что я могу создать 4 потока, скажем, я создал 4 потока, чем как я должен назначить работу каждому потоку .? - person ATG; 10.07.2012
comment
Можете ли вы сказать мне какие-либо материалы для чтения, где я могу прочитать об этом и лучше понять.?? - person ATG; 10.07.2012
comment
По сути, вам нужно иметь возможность разбить задачу на подзадачи, которые можно поставить в очередь. Затем каждый поток вытаскивает свою задачу из очереди, когда поток завершается, получает следующую задачу. Я добавлю еще некоторые детали. - person Brady; 10.07.2012
comment
Я делаю умножение матриц, так как я могу разделить это на разные задачи?? - person ATG; 10.07.2012
comment
@user1140170 user1140170, если его нельзя разделить, то, возможно, многопоточность не решение. - person Brady; 10.07.2012
comment
@ user1140170: Вы все еще ищете? Я мог бы продемонстрировать стратегию, если вы опубликуете новый вопрос об этом. - person Tudor; 10.07.2012
comment
@ user1140170, я добавил больше информации в свой ответ. Есть несколько областей, которые вы должны исследовать: пулы потоков, очередь производителей/потребителей, переменные состояния pthread, которые выходят за рамки этого вопроса, но с помощью простого поиска вы должны найти то, что вам нужно :) - person Brady; 10.07.2012
comment
@Brandy: спасибо, я пытаюсь разделить это на разные задачи.!! - person ATG; 10.07.2012
comment
Или вы можете выполнить параллельную декомпозицию данных по внешнему циклу. - person Tudor; 10.07.2012
comment
@Tudor, может быть, вы могли бы объяснить это в отдельном ответе, похоже, вы знаете больше об умножении матриц, чем я :) - person Brady; 10.07.2012
comment
@Brady: Я мог бы это сделать, но я бы предпочел, чтобы он опубликовал новый вопрос об этом, потому что на этот вопрос ответили вы. Технически этот вопрос был: «Почему моя программа работает медленнее с потоками, чем без?», который вы правильно объяснили. - person Tudor; 10.07.2012
comment
@Tudor, хорошо, звучит разумно. Должен ли он называться как-то вроде «Как разделить умножение массива на потоковые задачи» или что-то подобное? - person Brady; 10.07.2012