zoukankan      html  css  js  c++  java
  • C++ openmp并行程序在多核linux上如何最大化使用cpu

    以上代码中,#pragma omp parallel for

    这一行的作用即是调用openmp的功能,根据检测到的CPU核心数目,将for (i = 0; i < 1000000000; i++)这个循环执行过程平均分配给每一个CPU核心

    去掉#pragma omp parallel for这行,则和普通的串行代码效果一致。

    注意,要使用openmp功能,在编译的时候需要加上-fopenmp编译参数。

    以下是两种编译搭配两种代码出现的4种结果,可以很直观地看到效果:

    1、代码里含有#pragma omp parallel for,编译参数有-fopenmp

    Endys-MacBook-Pro:Desktop endy$ vi test.c 

    Endys-MacBook-Pro:Desktop endy$ gcc-6 test.c -o test -fopenmp

    Endys-MacBook-Pro:Desktop endy$ ./test 

    Program costs 50202611.00 clock tick.

    2、代码里含有#pragma omp parallel for,编译参数没有-fopenmp

    Endys-MacBook-Pro:Desktop endy$ gcc-6 test.c -o test

    Endys-MacBook-Pro:Desktop endy$ ./test 

    Program costs 4068178.00 clock tick.

    3、代码里没有#pragma omp parallel for,编译参数有-fopenmp

    Endys-MacBook-Pro:Desktop endy$ vi test.c 

    Endys-MacBook-Pro:Desktop endy$ gcc-6 test.c -o test -fopenmp

    Endys-MacBook-Pro:Desktop endy$ ./test 

    Program costs 4090744.00 clock tick.

    4、代码里没有#pragma omp parallel for,编译参数没有-fopenmp

    Endys-MacBook-Pro:Desktop endy$ vi test.c 

    Endys-MacBook-Pro:Desktop endy$ gcc-6 test.c -o test

    Endys-MacBook-Pro:Desktop endy$ ./test 

    Program costs 4170093.00 clock tick.

    可以看出,只有在情况1下,openmp生效,其他3种情况下,均为单核运行,2、3、4结果较为接近,而1的运行结果大约相差25%。

    值得注意的是,使用多核心的case 1竟然比单核的其他3种case慢了25%,原因是在这种单一的循环运算中,并行分配CPU任务的指令比直接执行下一个循环指令的效率更低。所以并不是用并行运算就一定能够提高运算效率的,要根据实际情况来判断。

    #include<stdio.h>
    #include<time.h>
    #include<omp.h>
    int main()
    {
        long long i;
        clock_t t1,t2;
        double t3,sum=0;
        t1=clock();
    
        #pragma omp parallel for
        {
            //#pragma omp 
            for(int j=0;j<200;j++)
            {
                for(i=0;i<=1000000000;i++)
                {
                    sum=sum+i/100;
                }
                printf("%d
    ",j);
            }
        }
    
        t2=clock();
        t3 =t2-t1;
        t3 = t3/CLOCKS_PER_SEC;
        printf("%f s
    ",t3);
        return 0;
    }

    这个代码能体现openmp 的功能

    1.另外注意哪些可以并行

    2.哪些不能并行

    3.简单的不需要并行,可能会比串行花费更多时间

    在linux g++下的命令如下:

    g++ program.cpp -o program -fopenmp

    或者:g++ -fopenmp grogram.cpp -o program

    ./program

     继续上面的例子来说:

    上述代码中求出的sum有误。因为sum是共享的,那么多个线程对sum的操作会引发数据竞争。

    解决办法:reduction

    #include<stdio.h>
    #include<time.h>
    #include<omp.h>
    #include<vector>
    using namespace std;
    int main()
    {
        long long i;
        clock_t t1,t2;
        double t3,sum1=10,sum2=0;
        t1=clock();
        vector<int>ve;
        printf("ID: %d, Max threads: %d, Num threads: %d 
    ",omp_get_thread_num(), omp_get_max_threads(), omp_get_num_threads());
        #pragma omp parallel for reduction(+: sum1,sum2)
            for(int j=0; j<100; j++)
            {
                sum1+=1;
                sum2+=2;
                printf("%d %f %f
    ",j,sum1,sum2);
            }
    
        t2=clock();
        t3 =t2-t1;
        t3 = t3/CLOCKS_PER_SEC;
        printf("%f s	 %f	 %f
    ",t3,sum1,sum2);
        return 0;
    }

    reduction声明可以看作:

    1. 保证了对sum的原则操作

    2. 多个线程的执行结果通过reduction中声明的操作符进行计算,以加法操作符为例:

    假设sum的初始值为10(如上述代码中),reduction(+: sum)声明的并行区域中每个线程的sum初始值为0(规定),

    并行处理结束之后,会将sum的初始化值10以及每个线程所计算的sum值相加。

    reduction (operator: var1, val2, ...)

    其中operator以及约定变量的初始值如下:

    运算符            数据类型                  默认初始值

    +                   整数、浮点               0

    -                    整数、浮点               0

    *                   整数、浮点               1

    &                   整数                        所有位均为1

    |                    整数                        0
    ^                   整数                        0

    &&                 整数                        1

    ||                   整数                        0

    vector 并行插入问题:

    std::vector<int> vec;
    #pragma omp parallel
    {
        std::vector<int> vec_private;
        #pragma omp for nowait //fill vec_private in parallel
        for(int i=0; i<100; i++) {
            vec_private.push_back(i);
        }
        #pragma omp critical
        vec.insert(vec.end(), vec_private.begin(), vec_private.end());
    }
    #pragma omp critical保证执行完子线程后,在执行主线程


  • 相关阅读:
    python的生成Jwt
    qq邮箱验证
    DJango反序列化器的参数效验
    python三元运算,继承,help函数 args
    python时间板块,计算取值,math函数
    No migrations to apply. django同步数据库失败
    redis理论部分
    Java入门——day1
    HBO《硅谷》中的二进制码
    复习总表现(每天记录一下)
  • 原文地址:https://www.cnblogs.com/XDJjy/p/7619737.html
Copyright © 2011-2022 走看看