Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 线程矩阵乘法:为什么不能更快?_C_Multithreading - Fatal编程技术网

C 线程矩阵乘法:为什么不能更快?

C 线程矩阵乘法:为什么不能更快?,c,multithreading,C,Multithreading,所以我一直在玩pthreads,特别是试图计算两个矩阵的乘积。我的代码非常混乱,因为我认为它只是一个快速有趣的项目,但我使用的线程理论非常类似于: #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define M 3 #define K 2 #define N 3 #define NUM_THREADS 10 int A [M][K] = { {1,4}, {2,5}, {3,6}

所以我一直在玩pthreads,特别是试图计算两个矩阵的乘积。我的代码非常混乱,因为我认为它只是一个快速有趣的项目,但我使用的线程理论非常类似于:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define M 3
#define K 2
#define N 3
#define NUM_THREADS 10

int A [M][K] = { {1,4}, {2,5}, {3,6} };
int B [K][N] = { {8,7,6}, {5,4,3} };
int C [M][N];

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

void *runner(void *param); /* the thread */

int main(int argc, char *argv[]) {

   int i,j, count = 0;
   for(i = 0; i < M; i++) {
      for(j = 0; j < N; j++) {
         //Assign a row and column for each thread
         struct v *data = (struct v *) malloc(sizeof(struct v));
         data->i = i;
         data->j = j;
         /* Now create the thread passing it data as a parameter */
         pthread_t tid;       //Thread ID
         pthread_attr_t attr; //Set of thread attributes
         //Get the default attributes
         pthread_attr_init(&attr);
         //Create the thread
         pthread_create(&tid,&attr,runner,data);
         //Make sure the parent waits for all thread to complete
         pthread_join(tid, NULL);
         count++;
      }
   }

   //Print out the resulting matrix
   for(i = 0; i < M; i++) {
      for(j = 0; j < N; j++) {
         printf("%d ", C[i][j]);
     }
      printf("\n");
   }
}

//The thread will begin control in this function
void *runner(void *param) {
   struct v *data = param; // the structure that holds our data
   int n, sum = 0; //the counter and sum

   //Row multiplied by column
   for(n = 0; n< K; n++){
      sum += A[data->i][n] * B[n][data->j];
   }
   //assign the sum to its coordinate
   C[data->i][data->j] = sum;

   //Exit the thread
   pthread_exit(0);
}
#包括
#包括
#包括
#定义m3
#定义k2
#定义n3
#定义NUM_线程10
int A[M][K]={{1,4},{2,5},{3,6};
int B[K][N]={{8,7,6},{5,4,3};
国际货币基金组织[M][N];
结构v{
int i;/*行*/
int j;/*列*/
};
无效*流道(无效*参数);/*线*/
int main(int argc,char*argv[]){
int i,j,计数=0;
对于(i=0;ii=i;
数据->j=j;
/*现在,创建将数据作为参数传递给它的线程*/
pthread\u t tid;//线程ID
pthread\u attr\u t attr;//线程属性集
//获取默认属性
pthread_attr_init(&attr);
//创建线程
pthread_创建(&tid,&attr,runner,data);
//确保父线程等待所有线程完成
pthread_join(tid,NULL);
计数++;
}
}
//打印出结果矩阵
对于(i=0;ii][n]*B[n][数据->j];
}
//将总和指定给其坐标
C[数据->i][data->j]=总和;
//退出线程
pthread_退出(0);
}
资料来源:

对于非线程版本,我使用了相同的设置(3个2-d矩阵,动态分配结构来保存r/c),并添加了一个计时器。第一次试验表明,非线程版本速度更快。我的第一个想法是尺寸太小,无法注意到差异,创建线程需要更长的时间。所以我将尺寸增加到大约50x50,随机填充,然后运行它,我仍然没有看到线程版本的任何性能升级


我在这里遗漏了什么?

除非您使用的是非常大的矩阵(数千行/列),否则您不太可能从这种方法中看到很大的改进。就CPU时间而言,在现代CPU/OS上设置线程实际上相当昂贵,比几个乘法操作花费的时间多得多

此外,通常不值得为每个可用的CPU核心设置多个线程。例如,如果您只有两个内核,并且设置了2500个线程(用于50x50矩阵),那么操作系统将花费所有的时间在这2500个线程之间进行管理和切换,而不是进行计算


如果您事先设置了两个线程(仍然假设使用双核CPU),让这些线程在等待工作时始终可用,并向它们提供需要在某种同步工作队列中计算的2500个点积,那么您可能会开始看到改进。但是,它仍然不会比只使用一个内核好50%以上。

您不允许太多的并行执行:您在创建线程后立即等待线程,因此您的程序几乎无法使用额外的CPU(即,它永远不能使用第三个CPU/内核)。试着让更多的线程运行(可能会达到您拥有的内核数)。

我不完全确定我是否理解源代码,但它看起来是这样的:您有一个运行m*N次的循环。每次通过循环时,都会创建一个线程,该线程在结果矩阵中填充一个数字。但是,在启动线程之后,就要等待它完成。我不认为你实际上运行的线程不止一个


即使您运行了多个线程,该线程所做的工作也微不足道。即使K很大(您提到50),50次乘法与开始线程的成本相比也不算多。程序应该创建更少的线程(当然不超过处理器的数量),并为每个线程分配更多的工作。

如果处理器有两个内核,那么您应该将要完成的工作分成两部分,并为每个线程分配一半。如果你有3,4,5个核,同样的原理。最佳性能设计将始终使线程数与可用内核数相匹配(可用的意思是其他进程尚未大量使用的内核)

另一件事你必须考虑的是,每个线程必须具有与其他线程的数据连续且独立的数据。否则,memcache未命中将显著降低处理速度

为了更好地理解这些问题,我推荐《并行编程模式》一书


尽管它的代码示例更多地针对OpenMP和MPI,并且您正在使用PThreads,但本书的前半部分仍然非常丰富地介绍了多线程环境的基本概念和内部工作,对于避免您将遇到的大多数性能瓶颈非常有用。

如果代码正确并行(我不检查它),只有当代码在硬件中并行化时,性能才可能提高,即线程实际上是并行的(多核、多CPU……其他技术……),而不是明显的(“多任务”方式)并行。只是一个想法,我不确定情况是否如此。

您在哪种处理器上运行它?如果它不是多线程或双核的,您将看不到使用多线程的任何优势。事实上,为了同时运行两个线程而必须进行的上下文切换实际上会造成伤害