2

在 c# 聊天中一直在讨论这个问题。原来的问题是这样的:

计算例如 (Int32) 5+5 比 1234723847+32489237 快吗?

我最初的想法是在二进制级别进行优化以忽略填充零,因此较小的数字会更快。

所以,我测试了它。如果你有兴趣,这里是程序。如果没有,请直接跳到结果。

Stopwatch sw = new Stopwatch();
Int64 c = 0;
long msDifferential = 0;     //
int reps = 10; //number of times to run the entire program
for (int j = 0; j < reps; j++)
{            
    sw.Start();  //                
    sw.Stop();   // Just in case there's any kind of overhead for the first Start()
    sw.Reset();  //

    sw.Start();  //One hundred million additions of "small" numbers
    for (Int64 i = 0, k = 1; i < 100000000; i++, k++)
    {   
        c = i + k;
    }
    sw.Stop();

    long tickssmall = sw.ElapsedTicks;       
    long mssmall = sw.ElapsedMilliseconds;

    sw.Reset();

    sw.Start();  //One hundred million additions of "big" numbers
    for (Int64 i = 100000000000000000, k = 100000000000000001; i < 100000000100000000; i++, k++)
    {
        c = i + k;
    }
    sw.Stop();

    long ticksbig = sw.ElapsedTicks;
    long msbig = sw.ElapsedMilliseconds;

    //total differentials for additions
    ticksDifferential += ticksbig - tickssmall;   
    msDifferential += msbig - mssmall;                
}

//average differentials per 100000000 additions
long averageDifferentialTicks = ticksDifferential / reps;
long averageDifferentialMs = msDifferential / reps;

//average differentials per addition
long unitAverageDifferentialTicks = averageDifferentialTicks / 100000000;
long unitAverageDifferentialMs = averageDifferentialMs / 100000000;

System.IO.File.AppendAllText(@"C:\Users\phillip.schmidt\My Documents\AdditionTimer.txt", "Average Differential (Ticks): " + unitAverageDifferentialTicks.ToString() + ", ");
System.IO.File.AppendAllText(@"C:\Users\phillip.schmidt\My Documents\AdditionTimer.txt", "Average Differential (Milliseconds): " + unitAverageDifferentialMs.ToString());

结果

调试模式

  • 平均单位差:2.17 纳秒

发布模式(已启用优化)

  • 平均单位差:0.001 纳秒

发布模式(已禁用优化)

  • 平均单位差:0.01 纳秒

因此,在调试模式下,“大”数字每次相加比“小”数字加起来要长约 2.17 纳秒。但是,在发布模式下,差异几乎没有那么显着。


问题

所以我有几个后续问题:

  1. 哪种模式最适合我的目的?(调试、发布、发布(无选择))
  2. 我的结果准确吗?如果是这样,速度差异的原因是什么?
  3. 为什么调试模式的差异如此之大?
  4. 还有什么我应该考虑的吗?
4

1 回答 1

2

特定优化的效果将取决于您的编译器。您应该查看每种情况下生成的汇编代码并比较生成的 CPU 指令。在 CPU 级别上,如果生成相同的指令,性能应该不会因您添加的值而有任何差异。CPU 有一个时钟信号,如果在相同大小的操作数上执行相同的指令,则无论操作数的位是 1 还是 0,简单的算术运算都将采用相同数量的时钟滴答。内存效应可能会影响性能,但这里的数据足够小,这可能无关紧要。在反汇编中,您可以检查您的变量是否最终出现在寄存器中。如果不,有人可能想知道,如果只有几个变量对较大数据起重要作用的影响(如缓存命中/未命中、物理内存访问等)在这里也很重要。它们可能会,因为您的 CPU 每秒能够进行数十亿次算术运算,但 RAM 是一个速度较慢的外部设备。无论如何,这种影响是随机的,而不取决于您添加的值是大还是小。流水线停顿、指令重新排序等也应如此。在一系列实验中,在不同时间执行,平均时间应该在误差范围内相同(您在发布模式下获得的差异肯定属于这一类)。因为您的 CPU 每秒能够进行数十亿次算术运算,但 RAM 是一个速度较慢的外部设备。无论如何,这种影响是随机的,而不取决于您添加的值是大还是小。流水线停顿、指令重新排序等也应如此。在一系列实验中,在不同时间执行,平均时间应该在误差范围内相同(您在发布模式下获得的差异肯定属于这一类)。因为您的 CPU 每秒能够进行数十亿次算术运算,但 RAM 是一个速度较慢的外部设备。无论如何,这种影响是随机的,而不取决于您添加的值是大还是小。流水线停顿、指令重新排序等也应如此。在一系列实验中,在不同时间执行,平均时间应该在误差范围内相同(您在发布模式下获得的差异肯定属于这一类)。

我看到可能存在差异的一种可能性是编译器不是直接通过 64 位指令而是使用多个 32 位指令来处理 64 位数字。在这种情况下,一个聪明的编译器可能会注意到你在某个循环中使用的值永远不会超过 32 位数字的限制,并发出只对单个 32 位值而不是组成两个 32 位值的指令。 64 位值。看看拆卸可以揭示是否是这种情况。

于 2012-09-13T17:32:23.463 回答