多线程C ++程序,以加速一个summatory循环

时间:2013-06-14 16:18:31

标签: c++ multithreading performance algorithm

我有一个从1到N迭代的循环,随着时间的推移需要一个模数和。但是N非常大,所以我想知道是否有办法通过利用多线程来修改它。

提供示例程序

for (long long i = 1; i < N; ++i)
   total = (total + f(i)) % modulus;

f(i)在我的情况下不是一个实际的函数,而是一个在这里占据空间的长表达式。把它放在那里说明目的。

5 个答案:

答案 0 :(得分:8)

是的,试试这个:

double total=0;
#pragma omp parallel for reduction(+:total)
for (long long i = 1; i < N; ++i)
  total = (total + f(i)) % modulus;

编译:

g++ -fopenmp your_program.c

就这么简单!不需要标头。 #pragma行自动旋转几个线程,均匀地划分循环的迭代,然后在循环之后重新组合所有内容。但请注意,您必须事先知道迭代次数。

此代码使用OpenMP,它提供了易于使用的并行性,非常适合您的情况。 OpenMP甚至内置于GCC和MSVC compilers

This page显示了一些可能的其他减少操作。

如果你需要嵌套for循环,你可以写

double total=0;
#pragma omp parallel for reduction(+:total)
for (long long i = 1; i < N; ++i)
for (long long j = 1; j < N; ++j)
  total = (total + f(i)*j) % modulus;

外部循环将被并行化,每个线程都运行自己的内部循环副本。

但您也可以使用collapse指令:

#pragma omp parallel for reduction(+:total) collapse(2)

然后两个循环的迭代将被自动分割。

如果每个线程都需要自己的循环之前定义的变量副本,请使用private命令:

double total=0, cheese=4;
#pragma omp parallel for reduction(+:total) private(cheese)
for (long long i = 1; i < N; ++i)
  total = (total + f(i)) % modulus;

请注意,您无需使用private(total),因为reduction暗示了这一点。

答案 1 :(得分:2)

假设f(i)是独立的,但大致相同的时间运行,你可以创建自己的4个线程,并让每个线程总和为总数的1/4,然后将总和作为值返回,加入每一个。这不是一种非常灵活的方法,特别是如果f(i)次的时间可以是随机的。

您可能还想考虑一个线程池,并让每个线程计算f(i)然后得到下一个i来求和。

答案 2 :(得分:0)

如果您正在使用c ++ 11,则可以使用threading building blocks和lambda函数。比你的循环看起来像:

tbb::parallel_for(1, N, [=](long long i) {
  total = (total + f(i)) % modulus;
});

和whitout溢出检查:

tbb::parallel_for(1, N, [=](long long i) {
  total = (total + f(i));
});
total %= modulus;

答案 3 :(得分:0)

尝试使用openMP的并行for total http://bisqwit.iki.fi/story/howto/openmp/#ReductionClause

的缩减条款

答案 4 :(得分:0)

如果f(long long int)是一个完全依赖于它的输入而没有全局状态和加法保持的阿贝尔属性的函数,那么你可以获得这样的显着优势:

for(long long int i = 0, j = 1; i < N; i += 2, j += 2)
{
    total1 = (total1 + f(i)) % modulus;
    total2 = (total2 + f(j)) % modulus;
}

total = (total1 + total2) % modulus;

通过允许编译器改进代码生成和CPU使用更多资源(两个操作可以并行处理)并将更多数据输出并减少停顿来解决这个 帮助。 [我在这里假设一个x86架构]

当然,如果不知道f的真实情况,很难确定这是否可能,或者它是否真的会有所帮助或产生可衡量的差异。

可能还有其他类似的技巧,您可以利用您的输入和平台的特殊知识 - 例如,SSE指令可以让您做更多。特定于平台的功能也可能很有用。例如,可能根本不需要模运算,并且您的编译器可能提供特殊的内部函数来执行加法模N.

我必须问一下,你有没有对你的代码进行分析并发现这是一个热点?