多个嵌套for循环与单个for循环 我在C++中做了一个小速度测试,得到了奇怪的结果。我正在测试使用一个for循环与多个嵌套for循环的速度。代码如下: double testX = 0; // Single loop executes in roughly 0.04 seconds for( int i = 0; i < 27000000; i++ ){ testX += 1; } // Nested loop executes in roughly 0.03 seconds for( int x = 0; x < 300; x++ ){ for( int y = 0; y < 300; y++ ){ for( int z = 0; z < 300; z++ ){ testX += 1; } } } double testX=0; //单循环大约在0.04秒内执行 对于(int i=0;i

多个嵌套for循环与单个for循环 我在C++中做了一个小速度测试,得到了奇怪的结果。我正在测试使用一个for循环与多个嵌套for循环的速度。代码如下: double testX = 0; // Single loop executes in roughly 0.04 seconds for( int i = 0; i < 27000000; i++ ){ testX += 1; } // Nested loop executes in roughly 0.03 seconds for( int x = 0; x < 300; x++ ){ for( int y = 0; y < 300; y++ ){ for( int z = 0; z < 300; z++ ){ testX += 1; } } } double testX=0; //单循环大约在0.04秒内执行 对于(int i=0;i,c++,for-loop,nested,timing,C++,For Loop,Nested,Timing,正如你所看到的,速度差异是相当明显的。我已经运行了很多次,这些是我看到的平均时间(这些时间是使用glfwGetTime()计时的) 所以我的问题是:为什么?我的测试方法是否不足?我使用的循环太少了吗?我试过搜索谷歌,我能找到的唯一一个类似的问题是他的问题与缓存一致性有关,但由于这些都是空的for循环,我认为这不会产生真正的效果 感谢您的帮助:) 编辑:多亏了这些评论,我意识到使用空for循环可能不是最好的测试方法。。。因此,我更新了我的代码,将一些(非常)简单的操作修改为double。我也在发布

正如你所看到的,速度差异是相当明显的。我已经运行了很多次,这些是我看到的平均时间(这些时间是使用glfwGetTime()计时的)

所以我的问题是:为什么?我的测试方法是否不足?我使用的循环太少了吗?我试过搜索谷歌,我能找到的唯一一个类似的问题是他的问题与缓存一致性有关,但由于这些都是空的for循环,我认为这不会产生真正的效果

感谢您的帮助:)

编辑:多亏了这些评论,我意识到使用空for循环可能不是最好的测试方法。。。因此,我更新了我的代码,将一些(非常)简单的操作修改为double。我也在发布模式下编译。然而,尽管这两种方法在时间上非常相似,但第二种方法仍然稍快一些


是的,这是所有的测试代码(不包括计时/输出函数,但这些并不是问题的具体内容)。

您最好的办法是查看反汇编并检查生成代码中的差异,我想编译器会在那里进行一些非常重量的优化。

如果您不使用
变量(
x
y
z
)在
for
循环中,智能编译器可以(也应该)实现在单个
for
循环中转换第二个表单,而无需嵌套。除非通过让用户在运行时从
stdin
输入
x
y
z
值,或从某个流中读取等方式,防止此类编译器优化消除静态可预测性

此外,如果不使用
testX
变量(例如,将其打印到
stdout
),智能编译器可以(而且应该)优化它,即完全删除死代码

因此,我要说的是,目前的基准测试在某种程度上是不正确的。

当在代码后面的某个地方使用testX变量时,编译器不会“优化”循环。当我只在代码中添加一行以输出testX时,结果如下所示:

  • 单循环:1.218ms
  • 为循环嵌套:1.218 ms
这几乎表明编译器尽可能将嵌套循环转换为单个循环。循环索引可用于防止这种优化:

以这种方式修改代码

for( int i = 0; i < 27000000; i++ ){
    testX += i;
}
这避免了编译器的可预测性

结果(对于
lmt=300
病例,可比较):

  • 单循环:1.213 ms
  • 嵌套for循环:1.216 ms
结果:

  • 嵌套循环不比单个循环快

这真的是整个测试代码吗?代码什么都不做-编译器可以完全删除循环。你在for循环中做什么?它是空的吗(如问题中所示)?除非他想了解未优化构建的性能特征…@JeremyFriesner这是一件毫无意义的事情,即使使用该计数器,如果编译器不只是对其进行优化,我也会感到惊讶。我想知道编译器是否展开了最内部的循环,何时不展开,这是否会提高速度。智能编译r可以首先展开最里面的循环,并注意到结果是一个常量加法链,可以用一个加法替换。下一个外部循环现在只包含一条指令,因此它也是展开的一个很好的候选者。当编译器以递归方式展开和替换时,它可以替换ole three for循环加一个加法。@Philipp:True,但如果编译器出于某种原因害怕/禁止使用大循环计数器展开循环,它会/可能会对单循环执行相同的操作。问题是:为什么嵌套结构更快?考虑到您的观点,可以相信嵌套循环更有可能由编译器部分或完全展开。换句话说:使用嵌套循环来简化编译器优化。有那么简单吗?我假设循环展开有一定的上限。当编译器展开一个2700万次迭代的循环时(结果不能用像这里这样的一个加法代替),它将创建一个超过100 MB的二进制文件,这对于二进制文件大小优化来说肯定比合理的速度快得多。@Philipp:是的!我刚刚在代码中添加了几行,以禁止展开以查看可能的差异。谢谢你的回答!我复制了你的(已编辑)代码,我现在得到的结果是单循环确实比嵌套循环快:)我的测试显然不够密集,有些东西正在编译。我仍然担心的一件事是,我的时间仍然在35和37毫秒左右,而你的时间在1毫秒左右。。。你在用什么编译器?
for( int x = 0; x < 300; x++ ){
    testX += x;
    for( int y = 0; y < 300; y++ ){
        testX += y;
        for( int z = 0; z < 300; z++ ){
            testX += z;
        }
    }
}
int lmt = rand() % 1 + 300;      // random value 300 or 301 
int big_lmt = lmt * lmt * lmt;   // random value 27000000 or 27270901

for( int i = 0; i < big_lmt; i++ ){
    testX += i;
}

for( int x = 0; x < lmt; x++ ){
    testX += x;
    for( int y = 0; y < lmt; y++ ){
        testX += y;
        for( int z = 0; z < lmt; z++ ){
            testX += z;
        }
    }
}