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");
}
结果如下:
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
测试是在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 次 | 
| 最近记录: |