代码优化向导第一部分

    这是一篇在网上看到的技术文章,它把一个原来需要6000毫秒的代码段优化到400毫秒,这种优化效果让我震撼,所以我决定把它翻译共享出来。

    下面是原文链接:http://www.codeproject.com/Articles/381630/Code-optimization-tutorial-Part-1

简介:

    这篇文章是尝试把代码优化技术介绍给软件开发者。为些,我们将探究各种优化的方法。
    第一步,我选取一段容易理解的算法代码段,并在上面运用各种不同的优化方法。
    我们要解决的问题是3n+1猜想(关于这个问题的详细解释大家可以点这个链接 3n+1问题详细),
    我们执行一个从1到1000000的循环,每个数都套用这个函数:
    
    直到n变成1,我们再执行下一个数,我们不需要从键盘上读取任何数据程序就可以打印结果,并且我们可以计算出运行的时间,用来做测试的设备是:   AMD Athlon 2 P340 Dual Core 2.20 GHz, 4 GB of RAM, Windows 7 Ultimate x64。测试的语言是:C#和C++
    代码的第一个版本:为1到1000000中的每个数执行上面的算法,算法会产生一系列的数字,直到等于1时才会停止,归1的步骤数将会被记录下来,并且最大的步骤数将会被确定下来。
C++代码段:
for (int i = nFirstNumber; i < nSecondNumber; ++i)
{
    int nCurrentCycleCount = 1;
    long long nNumberToTest = i;
    while (nNumberToTest != 1)
    {
        if ((nNumberToTest % 2) == 1)
        {
            nNumberToTest = nNumberToTest * 3 + 1;
        }
        else
        {
            nNumberToTest = nNumberToTest / 2;
        }
        nCurrentCycleCount++;
    }
    if (nCurrentCycleCount > nMaxCycleCount)
    {
        nMaxCycleCount = nCurrentCycleCount;
    } 
}  
C#代码段:
for (int i = FirstNumber; i < SecondNumber; ++i)
{
    int iCurrentCycleCount = 1;
    long iNumberToTest = i;
    while (iNumberToTest != 1)
    {
        if ((iNumberToTest % 2) == 1)
        {
            iNumberToTest = iNumberToTest * 3 + 1;
        }
        else
        {
            iNumberToTest = iNumberToTest / 2;
        }
        iCurrentCycleCount++;
    }
    if (iCurrentCycleCount > MaxCycleCount)
    {
        MaxCycleCount = iCurrentCycleCount;
    }
} 

    我用Debug和Release模式以及32位和64位分别执行了这段代码,然后我每次都运行100次取平均值(单位是ms)。下面是运行的结果:
  C++ Debug C++ Release C#Debug C# Release
x86 version 6882 6374 6358 5109
x64  versiong 1020 812 1890 742

    我们从表里面看到的第一点是,32位的程序要比64位的慢5到7倍,因为x64设计是一个寄存器可以存储一个long long数据,而x86而需要两个寄存器,所以在后面我们不再研究32位的程序。第二点是,Debug和Release所用的时间差距很大,特别是C#。第三点是,通过观察,C#编译器貌似比C++编译器在优化方面更胜一筹。
我提供的第一个优化动作是与数学操作符有关的,我用非传统的方式替换传统的方式。我们可以看到上面的代码里面只有三个复杂的数学操作符:%,*,/。首先我要优化的是%2操作,我们发现只要与0x1做&操作就可以判断一个数是否是奇数。所以当我们执行下面的替换时:
if ((nNumberToTest % 2) == 1)
替换成:
if ((nNumberToTest & 0x1) == 1)
下面是新的结果表:
C++ Debug C++ Release C# Debug C# Relase
922 560 1641 714

    我们发现,C++ Release版本得到了很大的优化,Release和Debug版本的优化程序不同让我相信,在Release版本下编译器会删除多余的指令。C#则好像没有太大的优化。下一个优化的动作是/2操作,我们发现用位操作>>1与/2操作得到的是相同的效果, 所以当我们执行下面的替换时
nNumberToTest = nNumberToTest / 2;
替换成:
nNumberToTest = nNumberToTest >> 1;
下面是新的结果:
C++ Debug C++ Release C# Debug C# Relase
821 555 1432 652
    我们发现C++ Debug, C# Debug, C# Release有差不多65到200毫秒的优化,而C++ Release版本则好像没有优化一样,那是因为在这种模式下编译器已经做了这个转换操作。最我们能做的变换只能是把*换成+操作, 所以当我们执行下面的替换时
nNumberToTest = nNumberToTest * 3 + 1; 
替换成:
nNumberToTest = nNumberToTest + nNumberToTest + nNumberToTest + 1; 
下面是新的结果:

C++ Debug C++ Release C# Debug C# Relase
820 548 1535 629
原文地址:https://www.cnblogs.com/javawebsoa/p/3093464.html