2014-01-13 69 views
1

我在Objective-C的這些功能:爲什麼Objective-C sqrtf()函數比只返回值的函數更快?

-(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

我想sqrt()函數是C級,更接近系統,它使用寄存器數據類型。 –

+0

區別在於'emptyFunction'和'sqrtFunction'方法不是函數,'sqrt()'是像'AnoopVaidya'這樣的C級函數。方法是**不**功能有很大的區別。 – Popeye

回答

3

調用[self returnNr:i]與簡單調用C函數並不相同。相反,你要發送消息到self,這被翻譯成相當於C:

objc_msgSend(self, @selector(returnNr:), i); 

這最終會打電話給你returnNr:執行,但有一些涉及的開銷。有關在objc_msgSend這是怎麼回事更多詳情,請參閱objc_msgSend tourLet's build objc_msgSend

[編輯] 另請參閱An Illustrated History of objc_msgSend,它顯示瞭如何實現隨時間變化。由於在objc_msgSend的演變過程中所做的改進/折衷,在Q中執行代碼將導致不同平臺版本的結果不同。

+1

DAMN很好的答案。將_returnNr_更改爲一個簡單的C函數,它應該比_sqrtFunction_更快。感謝您的深入解釋。 –

1

你的OBJ-C方法

-(float)returnNr:(float)number 
{ 
    return number; 
} 

第一被編譯到C-函數,然後它被執行,並且sqrtf()是C-功能。因此與Objective-C方法相比,C-函數將更快。

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方法調用的情況下,編譯器遠不如優化機會,這將很可能總是假設一個方法調用可能有可能的副作用,必須調用總是。因此,第二次優化可能不會應用於優化版本。

此外,您測量已用時間的方法還遠遠不夠準確。您應該使用mach計時器來獲得精確的絕對時間。而且你需要執行一些「運行」,並取得最少的運行。