老谭笔记

关于计时的那些纠结

写程序就避免不了与时间打交道,在C和Objective-C里面有很多与时间有关的函数和类,那我们如果选用合理的计时方式呢?下面就分别对几种最常用的计时方式做出对比:

##用time()函数计时

在time.h里面有一个经常使用的时间函数叫做time(),它的原型为time_t time(time_t *),返回从1700年1月1日0点0分0秒到目前的秒数,所以它仅能够精确到秒,使用方式如下:

1
2
3
4
5
6
7
- (void)timeTest1
{
time_t time_start = time(NULL);
sleep(5);
time_t time_end = time(NULL);
NSLog(@"%ld",time_end-time_start);
}

用clock()函数计时

该函数定义在time.h之中,原型为clock_t clock(void),这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,将该数值除以CLOCKS_PER_SEC便可以换算出相应的时间(故它的精度与系统有关系,在OSX系统中CLOCKS_PER_SEC为1000,也就是可以精确到1微秒),所以我们常用它来计算一段代码执行需要多少时间,如:

1
2
3
4
5
6
7
- (void)timeTest2
{
clock_t clock_start = clock();
for(int i = 0; i < 2147483647; i++);
clock_t clock_end = clock();
NSLog(@"%f",(clock_end-clock_start)/(double)CLOCKS_PER_SEC);
}

不过需要注意的是,在类OSX系统中,sleep函数是不会消耗处理器时间,所以以下的代码打印的结果接近于0,而不是接近5:

1
2
3
4
5
6
7
- (void)timeTest2
{
clock_t clock_start = clock();
sleep(5);
clock_t clock_end = clock();
NSLog(@"%f",(clock_end-clock_start)/(double)CLOCKS_PER_SEC);
}

##用gettimeofday()函数计时

该函数定义在time.h之中,原型为gettimeofday(struct timeval , struct timezone ),参数1是保存获取时间结果的结构体,参数2用于保存时区结果,timeval的结构是:

1
2
3
4
5
struct timeval
{
long int tv_sec; // 秒数
long int tv_usec; // 微秒数
}

所以通过gettimeofday()可以获得精确到微秒数的时间,如下:

1
2
3
4
5
6
7
8
9
10
11
12
- (void)timeTest3
{
struct timeval daytime_start;
struct timezone timezone_start;
gettimeofday(&daytime_start, &timezone_start);
sleep(5);
struct timeval daytime_end;
struct timezone timezone_end;
gettimeofday(&daytime_end, &timezone_end);
NSLog(@"%f",(daytime_end.tv_sec-daytime_start.tv_sec)+(daytime_end.tv_usec-daytime_start.tv_usec)/(double)pow(10, 6));
}

##通过NSDate来获取时间

NSDate是Objective-C中用来描述时间和时期的对象,可以利用它更加方便的记录时间,它可以把时间精确到微秒,使用它来计时的示例代码:

1
2
3
4
5
6
- (void)timeTest4
{
NSDate *date = [NSDate date];
sleep(5);
NSLog(@"%f",-[date timeIntervalSinceNow]);
}