C语言 根据数组值为特定任务分配工作负载



我有一个特定的问题:我有一个2D矩阵,其中包含一些值,这些值对应于应该并行执行的任务。我想显式地将工作负载分配给特定的线程,其中ID对应于此数组的内容。作为测试,为了理解我应该做什么,我编写了以下简单代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>

int main(void)
{
int N=100; // Number of elements per dimension
int A[N][N], B[N][N]; // Matrices to work with
int i,j; // Loop indices
int nt; // Thread ID
int NT=4; //Number of threads
//Filling the arrays
for(i=0;i<N;i++)
for(j=0;j<N;j++)
A[i][j]=(i+j)%NT; //This is the value that corresponds to the task        we want to assign the job to

//Perform some operations   
#pragma omp parallel private(i,nt) num_threads(NT) 
{       
for(i=0;i<N;i++)
for(j=0;j<N;j++)
{               
nt = omp_get_thread_num();
if(A[i][j]==nt)
{
B[i][j]=nt;
//Some dummy operations to increase the load per thread
for (int k = 0; k < 100000ULL; ++k);
}
}       
}
printf("nnnn");
for(i=0;i<N;i++)
for(j=0;j<N;j++)
printf("A[%d][%d]=%d goes to thread %dn",i,j,A[i][j],B[i][j]);

return 1;

}

然而,在执行此操作时,我不确定这是否满足了最初的目的。所以问题是,如何显式地将工作负载分配给特定的线程?例如,矩阵的第一个元素由线程0执行,第二个由线程2执行,第三个由线程0执行,以此类推。根据我的理解,双for循环应该在并行区域之外执行,而不是在每个线程中执行,以减少总体工作量。

提前谢谢你

  1. 问题是你的代码变量j应该是私有的,所以使用private(i,j,nt)子句。最好将变量定义在最小所需范围内。在并行区域内定义的变量将是私有的。
  2. 另一个评论是,你必须检查你是否得到了所有你请求的线程。
if (NT != omp_get_num_threads()){
// You have less threads than requested, 
// handle this case here
}
  1. const int nt = omp_get_thread_num();应在for循环之前。调用这个函数一次就足够了。

  2. 如果你的目标是以循环的方式为线程分配不同的索引(矩阵):

thread   | indices assigned to the thread
-----------------------------------------
thread 0 | 0,0  0,4  0,8  etc...
thread 1 | 0,1  0,5  0,9  etc...
thread 2 | 0,2  0,6  0,10 etc...
thread 3 | 0,3  0,7  0,11 etc...

在这种情况下,你不需要辅助数组,你可以这样使用:

#pragma omp parallel
{       
const unsigned int NT = omp_get_num_threads();   // number of total threads
const unsigned int nt = omp_get_thread_num();    // current thread
for(unsigned int index = nt;index < N*N; index += NT)   
{
unsigned int i = index / N;
unsigned int j = index % N;
// Do whatever you have to do with indices i and j
printf("Indices i=%d, j=%d goes to thread %dn",i,j,nt);
}
}
  1. Performance:没有关于你真正的程序做什么的更多细节,我不能告诉你任何关于性能问题的事情。例如,由于错误的共享,像B[i][j]=...;这样写内存是一个真正的噩梦。

UPDATE:正如@Jim Cownie指出的,最简单的解决方案是使用schedule(static,1)子句,因为它以轮循的方式在线程之间分发工作。如果您将它与collapse(2)子句结合使用,您只需在串行代码中添加一行:

#pragma omp parallel for collapse(2) schedule(static,1) num_threads(NT) 
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{                           
// Do whatever you have to do with indices i and j
printf("Indices i=%d, j=%d goes to thread %dn",i,j,omp_get_thread_num());
}  

然而,这种解决方案有一个严重的缺点:在这种情况下,开销要大得多。

最新更新