多个嵌套for循环与单个for循环

时间:2012-09-14 04:43:51

标签: c++ for-loop nested timing

我在c ++(MSVS)中进行了一些速度测试并得到了一个奇怪的结果。我正在测试使用一个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;
        }
    }
}

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

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

任何帮助都是适当的:)

编辑:感谢评论,我意识到使用空for循环可能不是最好的测试方法...所以我已经更新了我的代码来做一些(非常)简单操作到双。我也在发布模式下编译。然而,尽管这两种方法在时间上更相似,但第二种方法仍然稍微快一些。

是的,这是所有的测试代码(减去时序/输出函数,但这些并不是特定的问题)。

3 个答案:

答案 0 :(得分:9)

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

  • single for loop: 1.218 ms
  • nested for loop: 1.218 ms

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

以这种方式修改代码

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

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;
        }
    }
}

会给嵌套循环增加一点开销,但执行时间会显示

  • single for loop: 1.224 ms
  • nested for loop: 1.226 ms

此处给出的时间平均超过30.000次循环运行。

注意:testX += x;仅在90000中贡献1,testX += x;仅在300中贡献1。因此,上述两个部分仍具有可比性。

嵌套循环并不比单循环慢得多,但您观察到它们更快是为真。

并且:您展示的时间大约是我观察次数的40倍。因为我在中速硬件上运行测试,所以我建议仔细检查编译器设置。也许glfwGetTime()的结果值得怀疑,这是您提问的主要原因。你有没有尝试过另一种计时方案?

编辑:为了防止编译器优化,可以选择循环限制为非常数:

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;
        }
    }
}

这避免了编译器的可预测性。

结果(lmt = 300案例具有可比性):

  • single for loop: 1.213 ms
  • nested for loop: 1.216 ms

结果:

  • 嵌套循环比单循环更快。

答案 1 :(得分:1)

如果您未在for循环中使用x变量(yzfor),则可以使用智能编译器(和应该)在没有嵌套的情况下在单个for循环中转换您的第二个表单。除非您通过让用户在运行时从x输入yzstdin值或从某些流中读取等来阻止此类编译器优化来消除静态可预测性。

此外,如果你没有对你的testX变量做任何事情(比如将其打印到stdout),智能编译器可以(并且应该)优化它,即删除死代码共

所以我所说的是,现在的基准测试在某种程度上是不合理的。

答案 2 :(得分:0)

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