3

我试图通过并行化矩阵乘法来提高相当复杂的迭代算法的性能,每次迭代都会调用矩阵乘法。该算法需要 500 次迭代和大约 10 秒。但是在并行化矩阵乘法之后,它会减慢到 13 秒。但是,当我单独测试相同维度的矩阵乘法时,速度有所提高。(我说的是 100x100 矩阵。)

最后,我关闭了算法内部的任何并行化,并在每次迭代中添加了以下代码,它完全没有任何作用,而且可能不会花费很长时间:

int j;

#pragma omp parallel for private(j)

for (int i = 0; i < 10; i++)
j = i;

同样,与没有这段代码的相同算法相比,速度降低了 30%。

因此,在主算法中使用 openmp 调用任何并行化 500 次会以某种方式减慢速度。这种行为对我来说看起来很奇怪,有人知道问题是什么吗?

主要算法由桌面应用程序调用,由 VS2010,Win32 版本编译。我在 Intel Core i3(并行化创建 4 个线程)、64 位 Windows 7 上工作。

这是一个程序的结构:

int internal_method(..)

{
...//no openmp here


 // the following code does nothing, has nothing to do with the rest of the program  and shouldn't take long,
 // but somehow adding of this code caused a 3 sec slowdown of the Huge_algorithm()
 double sum;
 #pragma omp parallel for private(sum)
 for (int i = 0; i < 10; i++)
    sum = i*i*i / (1.0 + i*i*i*i);

...//no openmp here
}


int Huge_algorithm(..)
{

 ...//no openmp here

    for (int i = 0; i < 500; i++)
    {
     .....// no openmp

     internal_method(..);

     ......//no openmp
    }

...//no openmp here
}

所以,最后一点是:单独调用并行代码 500 次(当算法的其余部分被省略时)需要不到 0.01 秒,但是当你在一个巨大的算法中调用它 500 次时,它会导致 3 秒的延迟整个算法。而我不明白的是小的并行部分如何影响算法的其余部分?

4

2 回答 2

2

对于 10 次迭代和一个简单的分配,我想与计算本身相比,OpenMP 开销太大了。这里看起来轻量级的东西实际上是管理和同步多个线程,这些线程甚至可能不是来自线程池。可能涉及一些锁定,我不知道 MSVC 在估计是否要并行化方面有多好。

尝试使用更大的循环体或更大数量的迭代(比如 1024*1024 迭代,仅用于初学者)。


示例 OpenMP Magick:

#pragma omp parallel for private(j)
for (int i = 0; i < 10; i++)
    j = i;

这可能会被编译器大致扩展为:

const unsigned __cpu_count = __get_cpu_count();
const unsigned __j  = alloca (sizeof (unsigned) * __cpu_count);
__thread *__threads = alloca (sizeof (__thread) * __cpu_count);
for (unsigned u=0; u!=__cpu_count; ++u) {
    __init_thread (__threads+u);
    __run_thread ([u]{for (int i=u; i<10; i+=__cpu_count)
                          __j[u] = __i;}); // assume lambdas
}

for (unsigned u=0; u!=__cpu_count; ++u)
    __join (__threads+u);

with __init_thread(),__run_thread()并且__join()是调用某些系统调用的非平凡函数。

如果使用线程池,您可以用alloca()类似的东西替换第一个__pick_from_pool()

(请注意,名称和发出的代码都是虚构的,实际实现会有所不同)


关于您更新的问题:

您似乎以错误的粒度进行并行化。将尽可能多的工作量放在一个线程中,所以而不是

 for (...) {
     #omp parallel ...
     for (...) {} 
 }

尝试

 #omp parallel ...
 for (...) {
     for (...) {} 
 }

经验法则:保持每个线程的工作负载足够大,以减少相对开销。

于 2012-07-13T10:35:21.597 回答
0

也许只是 j=i 对于 core-cpu 带宽来说不是高收益。也许你应该尝试一些更有效的计算。(例如取 i*i*i*i*i*i 并除以 i+i+i)

你是在多核 cpu 还是 gpu 上运行它?

于 2012-07-13T10:07:01.470 回答