我在Objective-C中有这些功能:
-(void)emptyFunction
{
NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];
float b;
for (int i=0; i<1000000; i++) {
b = [self returnNr:i];
}
NSTimeInterval endTime = [[NSDate date] timeIntervalSinceReferenceDate];
double elapsedTime = endTime - startTime;
NSLog(@"1. %f", elapsedTime);
}
-(float)returnNr:(float)number
{
return number;
}
和
-(void)sqrtFunction
{
NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];
float b;
for (int i=0; i<1000000; i++) {
b = sqrtf(i);
}
NSTimeInterval endTime = [[NSDate date] timeIntervalSinceReferenceDate];
double elapsedTime = endTime - startTime;
NSLog(@"2. %f", elapsedTime);
}
当我以任何顺序打电话给它时,它会在控制台中打印以下内容:
2014-01-13 12:23:00.458 RapidTest[443:70b] 1. 0.011970
2014-01-13 12:23:00.446 RapidTest[443:70b] 2. 0.006308
这是怎么回事? sqrtf()函数如何比仅返回值的函数快两倍?我知道sqrtf()适用于汇编语言这样的位,但是比返回更快?怎么可能?
答案 0 :(得分:3)
调用[self returnNr:i]
与简单调用C函数不同。相反,您正在向self
发送消息,该消息将转换为C:中的等效消息:
objc_msgSend(self, @selector(returnNr:), i);
这最终将调用你的returnNr:实现,但是涉及到一些开销。有关objc_msgSend
中发生的情况的更多详细信息,请参阅objc_msgSend tour或Let's build objc_msgSend
[编辑]
另请参阅An Illustrated History of objc_msgSend,其中显示了实施方式随时间的变化情况。由于objc_msgSend
演变过程中的改进/权衡,执行Q中的代码会导致不同平台版本产生不同的结果。
答案 1 :(得分:1)
你的Obj-C方法
-(float)returnNr:(float)number
{
return number;
}
首先编译为C函数然后执行,sqrtf()
是C函数。
因此,与Objective-C方法相比,C函数会更快。
答案 2 :(得分:1)
您的基准存在缺陷。
首先,在这两种情况下,编译器都可以按如下方式优化循环:
for (int i=0; i<1000000-1; i++) {
[self returnNr:i];
}
float b = [self returnNr:i];
分别为:
for (int i=0; i<1000000-1; i++) {
sqrtf(i);
}
float b = sqrtf(i);
然后,IFF编译器可以推断语句sqrtf(i)
没有副作用(除了返回值),它可以进一步优化如下:
float b = sqrtf(1000000-1);
clang很可能会应用此优化,但它依赖于实现。
另请参阅:Do C and C++ optimizers typically know which functions have no side effects?
在Objective-C方法调用的情况下,编译器具有更少的优化机会,并且很可能总是假设方法调用可能具有可能的副作用并且必须被称为始终。因此,第二次优化可能不会应用于优化构建中。
此外,您测量经过时间的方法到目前为止还不够准确。您应该使用马赫计时器来获得精确的绝对时间。而且你需要执行一些“运行”并花费最少的运行时间。