我有一个问题与OpenMP任务。我试图使用omp任务创建"for"循环的并行版本。但是,这个版本的执行时间比我使用omp for的基本版本长近2倍,我不知道这是什么原因。查看下面的代码:
omp for version:
t.start();
#pragma omp parallel num_threads(threadsNumber)
{
for(int ts=0; ts<1000; ++ts)
{
#pragma omp for
for(int i=0; i<size; ++i)
{
array_31[i] = array_11[i] * array_21[i];
}
}
}
t.stop();
cout << "Time of omp for: " << t.time() << endl;
omp任务版本:
t.start();
#pragma omp parallel num_threads(threadsNumber)
{
#pragma omp master
{
for(int ts=0; ts<1000; ++ts)
{
for(int th=0; th<threadsNumber; ++th)
{
#pragma omp task
{
for(int i=th*blockSize; i<th*blockSize+blockSize; ++i)
{
array_32[i] = array_12[i] * array_22[i];
}
}
}
#pragma omp taskwait
}
}
}
t.stop();
cout << "Time of omp task: " << t.time() << endl;
在tasks版本中,i按与omp for相同的方式划分循环。每个任务都必须执行相同数量的迭代。任务总数等于线程总数。
性能结果:
Time of omp for: 4.54871
Time of omp task: 8.43251
什么是问题?两个版本是否有可能实现相似的性能?附加的代码很简单,因为我想只说明我的问题,我试图解决。我不期望两个版本给我相同的性能,但是我希望减少差异。
感谢您的回复。致以最亲切的问候。
我认为这里的问题是开销。当你声明一个循环为并行循环时,它会让所有线程同时执行for循环的各自部分。当你启动一个任务时,它必须经历整个设置过程,每次你启动一个任务。为什么不这样做呢?
#pragma omp parallel num_threads(threadsNumber)
{
#pragma omp master
{
for(int ts=0; ts<1000; ++ts)
{
#pragma omp for
for(int th=0; th<threadsNumber; ++th)
{
for(int i=th*blockSize; i<th*blockSize+blockSize; ++i)
{
array_32[i] = array_12[i] * array_22[i];
}
}
}
}
}
我想说的是,你在这里实验的问题与数据亲和力有关:当你使用#pragma omp for
时,跨线程的迭代分布对于ts
的所有值总是相同的,而对于任务,你没有办法指定任务到线程的绑定。
曾经说过,我在我的机器上用三个1M元素的数组执行了你的程序,两个版本之间的结果更接近:
- t1_for: 2.041443 s
- t1_tasking: 2.159012 s
(我用的是GCC 5.3.0 20151204
)