Mär*_*ärs 3 precision parallel-processing multithreading openmp visual-c++
任何人都可以在单/多线程模式下解释/理解不同的计算结果吗?
这是一个约的例子.计算pi:
#include <iomanip>
#include <cmath>
#include <ppl.h>
const int itera(1000000000);
int main()
{
printf("PI calculation \nconst int itera = 1000000000\n\n");
clock_t start, stop;
//Single thread
start = clock();
double summ_single(0);
for (int n = 1; n < itera; n++)
{
summ_single += 6.0 / (static_cast<double>(n)* static_cast<double>(n));
};
stop = clock();
printf("Time single thread %f\n", (double)(stop - start) / 1000.0);
//Multithread with OMP
//Activate OMP in Project settings, C++, Language
start = clock();
double summ_omp(0);
#pragma omp parallel for reduction(+:summ_omp)
for (int n = 1; n < itera; n++)
{
summ_omp += 6.0 / (static_cast<double>(n)* static_cast<double>(n));
};
stop = clock();
printf("Time OMP parallel %f\n", (double)(stop - start) / 1000.0);
//Multithread with Concurrency::parallel_for
start = clock();
Concurrency::combinable<double> piParts;
Concurrency::parallel_for(1, itera, [&piParts](int n)
{
piParts.local() += 6.0 / (static_cast<double>(n)* static_cast<double>(n));
});
double summ_Conparall(0);
piParts.combine_each([&summ_Conparall](double locali)
{
summ_Conparall += locali;
});
stop = clock();
printf("Time Concurrency::parallel_for %f\n", (double)(stop - start) / 1000.0);
printf("\n");
printf("pi single = %15.12f\n", std::sqrt(summ_single));
printf("pi omp = %15.12f\n", std::sqrt(summ_omp));
printf("pi comb = %15.12f\n", std::sqrt(summ_Conparall));
printf("\n");
system("PAUSE");
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
PI calculation VS2010 Win32
Time single thread 5.330000
Time OMP parallel 1.029000
Time Concurrency:arallel_for 11.103000
pi single = 3.141592643651
pi omp = 3.141592648425
pi comb = 3.141592651497
PI calculation VS2013 Win32
Time single thread 5.200000
Time OMP parallel 1.291000
Time Concurrency:arallel_for 7.413000
pi single = 3.141592643651
pi omp = 3.141592648425
pi comb = 3.141592647841
PI calculation VS2010 x64
Time single thread 5.190000
Time OMP parallel 1.036000
Time Concurrency::parallel_for 7.120000
pi single = 3.141592643651
pi omp = 3.141592648425
pi comb = 3.141592649319
PI calculation VS2013 x64
Time single thread 5.230000
Time OMP parallel 1.029000
Time Concurrency::parallel_for 5.326000
pi single = 3.141592643651
pi omp = 3.141592648425
pi comb = 3.141592648489
Run Code Online (Sandbox Code Playgroud)
测试是在AMD和Intel CPU,Win 7 x64上进行的.
单核和多核PI计算差异的原因是什么?为什么Concurrency :: parallel_for的计算结果在不同的版本(编译器,32/64位平台)上不是常量?
PS Visual studio express不支持OpenMP.
由于舍入误差,浮点加法是非关联运算,因此操作顺序很重要.让并行程序给出与串行版本不同的结果是正常的.理解和处理它是书写(便携式)并行代码的一部分.由于在32位模式下VS编译器使用x87指令而x87 FPU执行内部精度为80位的所有操作,因此在32位对64位版本中会加剧这种情况.在64位模式下,使用SSE数学.
在串行情况下,一个线程计算s 1 + s 2 + ... + s N,其中N是扩展中的项数.
在OpenMP的情况下,有n个部分和,其中n是OpenMP线程的数量.哪些项进入每个部分和取决于迭代在线程之间分配的方式.许多OpenMP实现的默认值是静态调度,这意味着线程0(主线程)计算ps 0 = s 1 + s 2 + ... + s N/n ; 线程1计算ps 1 = s N/n + 1 + s N/n + 2 + ... + s 2N/n ; 等等.最后,减少以某种方式结合了那些部分和.
这个parallel_for案例与OpenMP非常相似.不同之处在于,默认情况下,迭代以动态方式分布 - 请参阅文档auto_partitioner,因此每个部分和包含或多或少的随机选项.这不仅会给出稍微不同的结果,而且每次执行时也会产生稍微不同的结果,即parallel_for具有相同线程数的两个连续的结果可能略有不同.如果用实例替换分区器simple_partitioner并将块大小设置为等于itera / number-of-threads,则如果以相同的方式执行缩减,则应获得与OpenMP情况相同的结果.
您可以使用Kahan求和并使用Kahan求和实现您自己的缩减.然后,并行代码应该产生与序列代码相同(更加相似)的结果.
我猜想,当浮点加法舍入误差得到更多分布时,openmp所做的并行缩减通常更准确.通常,由于舍入误差等原因,浮点数减少是有问题的.http://floating-point-gui.de/ 并行执行这些操作是通过分配舍入误差来提高准确性的一种方法.想象一下,你正在大幅度减少,在某些时候累加器的尺寸会比其他值大,这会增加每次加法的舍入误差,因为累加器范围要大得多,并且可能无法表示该范围内的较小值的值是精确的,但是如果有多个累加器用于相同的并联运算,它们的幅度将保持较小,这种误差会更小.
| 归档时间: |
|
| 查看次数: |
1423 次 |
| 最近记录: |