zoukankan      html  css  js  c++  java
  • 代码细节的终极优化之循环展开、多路并行

         直接上代码:

        

    
    

    void combine5(double data[],int length)
    {
    double sum = 0.0;
    for(int i=0;i<length;i++)
    {
    sum *= data[i];
    }
    cout<<sum<<endl;
    }
    void combine6(double data[],int length)
    {
    double sum = 0.0;
    int limit = length-1;
    int i;
    for(i=0;i<limit;i+=2)
    {
    sum = sum*data[i]*data[i+1];
    }
    for(;i<length;i++)
    {
    sum *= data[i];
    }
    cout<<sum<<endl;
    }
    void combine7(double data[],int length)
    {
    double sum1=0.0,sum2=0.0;
    int limit = length-1;
    int i;
    for(i=0;i<limit;i+=2)
    {
    sum1 *= data[i]; // 合并下标为偶数的值, 0按偶数算
    sum2 *= data[i+1]; // 合并下标为奇数的值
    }
    double sum = sum1*sum2;
    for(;i<length;i++)
    {
    sum *= data[i];
    }
    cout<<sum<<endl;
    }

     

       上面三个函数的功能是一样的,但是究其运行速度来说则不可同日语。为什么呢?

       由于加法器和乘法器是完全流水线化的,这代表着他们可以一个时钟周期执行多条指令,参见我前面写的那一篇博文(优化的小细节)。减小代码之间的相关性,增加代码的并行性,可以大幅度增加代码的执行效率,做到把CPU的能力都逼出来的地步。

       combine5只是做了一些简单的优化,combine6进行了循环展开,combine7既循环展开又多路并行。如果combine5运行时间是5,combine6的运行时间就会是2.5! combine7的运行时间就会是1!没错就是这么霸道!IA32以后的指令集都支持如此优化,但是绝大多数编译器都不会帮你把代码改成这个样子,所以自己写是最好的了。如果加上SSE的话,会把CPU的能力榨干的=。=  嘎嘎   下面来说说原因,为什么循环展开多路并行就比随便写快呢? 首先解释一个名词,叫关键路径,循环的效率主要取决于关键路径上的指令,循环的关键路径可以看成是贯穿整个循环的变量与计算,减少关键路径上的东西就等于加快了时间!那么循环展开就可以看成是减少了CPU走关键路径的次数,但是每次关键路径上的计算sum = sum*data[i]*data[i+1] 的相关性较大,两次乘法无法并行,因为第二次乘法必须等第一次乘法完毕才能执行。多路并行就可以解决这个问题,sum1 *= data[i]; sum2 *= data[i+1];这两个乘法互不依赖,完全可以并行,相当于只做了一次乘法,所以速度便大大加快了。

       从上面的分析会发现,循环展开三次,三路并行会比上面的代码更快,以此类推,代码的优化效率必然会趋近于一个极限值。这个极限值就是CPU的吞吐量界限了,理论上讲就无法再优化了。

  • 相关阅读:
    AtCoder Regular Contest 093
    AtCoder Regular Contest 094
    G. Gangsters in Central City
    HGOI 20190711 题解
    HGOI20190710 题解
    HGOI 20190709 题解
    HGOI 20190708 题解
    HGOI20190707 题解
    HGOI20190706 题解
    HGOI 20190705 题解
  • 原文地址:https://www.cnblogs.com/liboyan/p/5011382.html
Copyright © 2011-2022 走看看