2010-10-24 48 views
1

我有一個應用程序遍歷數組的每一步,當數組爲空時,我似乎得到令人驚訝的慢結果。所以,我調查了一些後續測試,如下所示:Objective-C空陣列性能

NSMutableArray* ar = [NSMutableArray array]; 
double time = CFAbsoluteTimeGetCurrent(); 
for (int i = 0; i < 10000; i++) 
{ 
    for (NSObject* obj in ar) 
    { 
     [obj retain]; 
     [obj release]; 
    } 
} 
time = CFAbsoluteTimeGetCurrent() - time; 
printf("Empty Time: %1.12f", time/10000.0f); 

time = CFAbsoluteTimeGetCurrent(); 
for (int i = 0; i < 10000; i++) 
{ 
    if ([ar count] > 0) 
    { 
     for (NSObject* obj in ar) 
     { 
      [obj retain]; 
      [obj release]; 
     } 
    } 
} 
time = CFAbsoluteTimeGetCurrent() - time; 
printf("Checked Time: %1.12f", time/10000.0f); 

我試過100次| 1,000 |萬個迭代週期,結果如下:

Empty Time: 0.000000039935   //100 
Checked Time: 0.000000020266  //100 
Empty Time: 0.000000018001   //1000 
Checked Time: 0.000000011027  //1000 
Empty Time: 0.000000015503   //10000 
Checked Time: 0.000000008899  //10000 

奇怪的是,這表明具有簡單地計算檢查顯著提高了低迭代運行性能(可能是因爲緩存方案)。這對我來說是絕對令人驚訝的,因爲我期望Objective-C編譯/運行時已經在執行foreach循環時執行此檢查!有沒有人有任何想法,爲什麼這可能是這種情況,如果有什麼辦法來擠出更多的性能出這個循環設置?謝謝!

回答

7

空數組在一個典型的Cocoa程序中不是很常見,也不會迭代數千次的空數組。

這將是非常令人驚訝的是有史以來看到空列陣列作爲CPU週期的重要消費者出現在樂器中。

鑑於基金會和核心基金會針對現實世界的績效模式進行了優化,因此沒有進行0計數檢查就不足爲奇了。

但是,如果你真的必須遍歷空數組一個bazillion倍,最快的方法是使用一個塊:

time = CFAbsoluteTimeGetCurrent(); 
[ar enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
    [obj retain]; 
    [obj release]; 
}]; 

我貼你的代碼爲基礎工具的main(),並得到了該上相對近期的MacBook Pro:

 Empty Time: 0.000000019896 
    Checked Time: 0.000000007498 
    Block Time: 0.000000000298 

當然,不是空數組,只需使用nil。即我在ar = nil;之後第二次完成了所有測試。

ar = nil; 
time = CFAbsoluteTimeGetCurrent(); 
for (int i = 0; i < 10000; i++) 
{ 
    for (NSObject* obj in ar) 
    { 
     [obj retain]; 
     [obj release]; 
    } 
} 
... etc ... 


     Empty Time: 0.000000019902 
    Checked Time: 0.000000007999 
     Block Time: 0.000000000298 
    nil Empty Time: 0.000000015599 
nil Checked Time: 0.000000004703 
    nil Block Time: 0.000000000000 

,總的來說,如果你的數據結構是複雜的,你是敲着他們多在每一幀渲染,我建議不同的數據結構可能是爲了。

當然,只有當您真的使用Instruments來對代碼進行採樣並且正在優化某些佔用整個CPU週期很大比例的東西時。

+0

HOLY POO!該塊的實現將執行時間縮短了100倍!它必須使用GCD來表現這種表現,是的?這非常不可思議,我將不得不考慮這一點。謝謝!哦,是的,我正在構建一個遊戲,所以遍歷空數組會發生在每一幀,因此空數組的性能非常重要。幸運的是,計數檢查沒有我想象的那麼糟糕(例如20行鍋爐代碼)。再次感謝! – Grimless 2010-10-24 20:48:11

+0

奇怪。我試過你的塊實現,它實際上使執行時間增加了三倍!這是我得到的:檢查時間:\t 0。000000009954空時間:\t \t 0.000000016987塊時間:\t \t 0.000000037014。注意:這已經完成了1000次,所以有可能塊創建實際上是造成這種情況的原因。編輯:是的,所以我擺脫了fori循環,並試圖直接塊運行,它減少了2倍的運行時間。好的解決方案 – Grimless 2010-10-24 20:56:35

+0

OOPS!忘了調整其他循環。是的,所以該塊的實施將運行時間增加了3倍......哎喲。 – Grimless 2010-10-24 21:02:32

-2

for-in構造不是免費的,它必須解決某種枚舉方法調用,所以報告的時間實際上是有意義的。在這種情況下,我會使用普通的C數組。如果你使用objc_msgsend()在這樣的大循環中調用objc方法,你也會獲得更好的性能。

+1

這個答案有兩個問題,我認爲沒有幫助和/或危險。舉例來說:由於數組的動態特性,我不能使用C數組;對象被一直添加到這些數組中並從中移除,使C數組的管理更加痛苦。其次:Objective-C引導明確說永遠不要明確調用objc_msgsend(),我打算堅持。 – Grimless 2010-11-30 00:18:25