为什么 `do{} while(0);` 很快?

4

我尝试了以下三个for循环:

#define loop 1000000000
NSDate *start;
NSDate *end;


// 1: empty for loop
start = [NSDate date];
for (NSInteger i = 0; i < loop; i++) {
}
end = [NSDate date];
NSLog(@"time interval: %f", [end timeIntervalSince1970] - [start timeIntervalSince1970]);


// 2: do-while for loop
start = [NSDate date];
for (NSInteger i = 0; i < loop; i++) {
    do {
    } while (0);
}
end = [NSDate date];
NSLog(@"time interval: %f", [end timeIntervalSince1970] - [start timeIntervalSince1970]);

// 3: @try-@finally for loop
start = [NSDate date];
for (NSInteger i = 0; i < loop; i++) {
    @try {
    }
    @finally {
    }
}
end = [NSDate date];
NSLog(@"time interval: %f", [end timeIntervalSince1970] - [start timeIntervalSince1970]);

我在我的'07年Macbook Pro上测试了这三个for循环约10亿次。我记录了时间戳以计算执行时间。以下是结果:

1: empty for loop => 2.947088 sec
2: do-while for loop => 2.581905 sec
3: @try-@finally for loop => 4.216685 sec

什么?do-while循环比空的for循环更快!

为什么?


更新

我在for循环中添加了一些额外的代码(j++):

NSInteger j;
#define loop 1000000000

// 1: empty for loop
j = 0
for (NSInteger i = 0; i < loop; i++) {
    j++;
}

// 2: do-while for loop
j = 0;
for (NSInteger i = 0; i < loop; i++) {
    do {
        j++;
    } while (0);
}

// 3: @try-@finally for loop
j = 0;
for (NSInteger i = 0; i < loop; i++) {
    @try {
        j++;
    }
    @finally {
    }
}

输出:

1: empty for loop => 2.590103 sec
2: do-while for loop => 2.138528 sec
3: @try-@finally for loop => 3.983589 sec

这三个代码比之前快得多,而do-while循环的for语句仍然是最快的。奇怪!


1
有趣,我也想知道为什么。 - JoeC
2
你尝试查看生成的汇编代码了吗?它可以回答你的问题。 - JIghtuse
1
在我的操作系统上,NSInteger 只是 long 类型(typedef long NSInteger;)。 - Xaree Lee
4
这些结果完全取决于编译器。如果您在使用具有不同优化机制的不同编译器时进行尝试,可能会得到不同的结果。 - Tharindu Rusira
3
优化后的微基准代码性能测试很困难。例如,如果您正在测试许多非常小的循环迭代,则循环指令的精确定位变得很重要。 - Greg Parker
显示剩余5条评论
1个回答

11

不是这样的。输出结果很大程度上取决于使用的特定编译器以及生效的优化设置。任何值得信赖的编译器都将优化掉这两个循环。当我编译以下示例代码时,无论是 Clang 还是 GCC,在任何非零优化级别(即 -O1 及以上)都会完全删除这些循环:

#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>

#define loop 1000000000

int main(void)
{
  struct timeval t1, t2, t3;
  gettimeofday(&t1, NULL);

  for (long i = 0; i < loop; i++) {
  }

  gettimeofday(&t2, NULL);

  for (long i = 0; i < loop; i++) {
    do {
    } while (0);
  }

  gettimeofday(&t3, NULL);

  int64_t d1 = (t2.tv_sec - t1.tv_sec) * 1000000ll + (t2.tv_usec - t1.tv_usec);
  int64_t d2 = (t3.tv_sec - t2.tv_sec) * 1000000ll + (t3.tv_usec - t2.tv_usec);

  printf("Empty for loop:    %lld.%06d\n", d1 / 1000000, (int)(d1 % 1000000));
  printf("do-while for loop: %lld.%06d\n", d2 / 1000000, (int)(d2 % 1000000));

  return 0;
}

在优化级别为0(-O0,未经优化的代码)时,Clang和GCC都会生成代码,其中两个循环以相同的速度运行(在实验误差范围内),或者do-while循环由于额外的未经优化的代码而运行得稍慢。 我在64位Mac上使用Clang 4.1和GCC 4.2.1得出的结果如下:

Clang, 32-bit, -O0:
Empty for loop:    2.632714
do-while for loop: 2.633194

Clang, 64-bit, -O0:
Empty for loop:    2.632078
do-while for loop: 2.632046

Clang, 32-bit, -O1:
Empty for loop:    0.000000
do-while for loop: 0.000000

Clang, 64-bit, -O1:
Empty for loop:    0.000000
do-while for loop: 0.000000

GCC, 32-bit, -O0:
Empty for loop:    2.633221
do-while for loop: 2.633754

GCC, 64-bit, -O0:
Empty for loop:    2.778056
do-while for loop: 2.983421  (!!!)

GCC, 32-bit, -O1:
Empty for loop:    0.000001
do-while for loop: 0.000000

GCC, 64-bit, -O1:
Empty for loop:    0.000000
do-while for loop: 0.000000

谢谢。我测试了你的代码。结果是:=> 空for循环:3.120945;=> do-while循环:2.164982。在Mac OS 10.9,'07 Macbook Pro,Xcode 5(iOS模拟器模式)上运行。但我想你说得对。 :) - Xaree Lee
4
打开编译器的优化功能。如果你启用了优化,如果出现不同的结果,我会非常惊讶。在没有启用优化的情况下测量性能几乎没有意义。 - Adam Rosenfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接