Objective-C 中如何測(cè)量代碼的效率

背景

在我們編程的時(shí)候,可能經(jīng)常會(huì)有一些疑問(wèn):?

* 我們寫(xiě)的某個(gè)方法的執(zhí)行效率是多少??

* 方法 A 和 方法 B 哪個(gè)更快?

因此,我們不可避免的要用到一些方法來(lái)計(jì)算代碼的執(zhí)行效率。計(jì)算代碼的執(zhí)行效率可以使用的API有:?

* NSDate?

* CFAbsoluteTimeGetCurrent?

* CACurrentMediaTime?

* dispatch_benchmark

NSDate

看到NSDate,大家應(yīng)該都能想到怎么使用吧。為了更直觀一點(diǎn),我還是使用代碼片段來(lái)演示好了:

NSTimeInterval startTime = [[NSDate new] timeIntervalSinceReferenceDate];NSLog(@"斐波那契數(shù):%d",fibonacci(10)) ;NSTimeInterval endTime = [[NSDate new] timeIntervalSinceReferenceDate];NSLog(@"耗時(shí):%f", endTime - startTime);

上面是一段 C與OC混合的代碼片段,計(jì)算斐波那契數(shù)列計(jì)算第10個(gè)數(shù)的值需要消耗的時(shí)間。

利用NSDate 來(lái)計(jì)算運(yùn)行效率:代碼段運(yùn)行前記錄一次時(shí)間,運(yùn)行后記錄一次,然后比較時(shí)間差。?

時(shí)間的單位是?秒

CFAbsoluteTimeGetCurrent

利用CFAbsoluteTimeGetCurrent 主要是利用CFAbsoluteTimeGetCurrent()函數(shù)來(lái)獲取當(dāng)前的絕對(duì)時(shí)間。同樣的我也是用代碼片段來(lái)演示:

CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();NSLog(@"斐波那契數(shù):%d",fibonacci(10)) ;CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();NSLog(@"耗時(shí):%f",endTime - startTime);

利用CFAbsoluteTimeGetCurrent 來(lái)計(jì)算運(yùn)行效率:代碼段運(yùn)行前記錄一次時(shí)間,運(yùn)行后記錄一次,然后比較時(shí)間差。?

時(shí)間的單位是?秒。

看到這里可能會(huì)有疑問(wèn)CFAbsoluteTimeGetCurrent()是如何獲取時(shí)間的呢??

我們追蹤進(jìn)去查看代碼,就會(huì)有答案了,這是源碼:

從CFTimeInterval的定義和注釋可以看出,CFAbsoluteTimeGetCurrent(void)返回的時(shí)間就是當(dāng)前時(shí)間相對(duì)與reference date的時(shí)間。?

CFTimeInterval?是對(duì)double 的重命名。?

而NSTimeInterval?也是對(duì)double 的重命名。?

它們之間的關(guān)系就可想而已了!?

CFAbsoluteTimeGetCurrent()?其實(shí)等價(jià)于?[[NSDate new] timeIntervalSinceReferenceDate]?。

CACurrentMediaTime

利用CACurrentMediaTime主要是利用CACurrentMediaTime()函數(shù)來(lái)計(jì)算時(shí)間。?

還是先用示例來(lái)演示用法:

CFTimeInterval startTime = CACurrentMediaTime();NSLog(@"斐波那契數(shù):%d",fibonacci(10)) ;CFTimeInterval endTime = CACurrentMediaTime();NSLog(@"耗時(shí):%f",endTime - startTime);

計(jì)算執(zhí)行效率時(shí)間上依然是:代碼段運(yùn)行前記錄一次時(shí)間,運(yùn)行后記錄一次,然后比較時(shí)間差。?

時(shí)間的單位是?秒。

跟蹤查看源碼中對(duì)CACurrentMediaTime()的定義

/* Returns the current CoreAnimation absolute time. This is the result of?* calling mach_absolute_time () and converting the units to seconds. */

CA_EXTERN CFTimeInterval CACurrentMediaTime (void)

? ? __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);

可以看出CACurrentMediaTime() 是對(duì)mach_absolute_time()的封裝。返回的是CoreAnimation 中的當(dāng)前時(shí)間。

dispatch_benchmark

dispatch_benchmark 是libdispatch(Grand Central Dispatch)的一部分。但嚴(yán)肅地說(shuō),這個(gè)方法并沒(méi)有被公開(kāi)聲明,所以我們必須要自己聲明:

extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));

第二個(gè)參數(shù)是執(zhí)行的代碼片段block。?

第一個(gè)參數(shù)是執(zhí)行的次數(shù)(即運(yùn)行block 的次數(shù))。

uint64_t t = dispatch_benchmark(1000000, ^{

? ? NSLog(@"斐波那契數(shù):%d",fibonacci(10)) ;

? });NSLog(@"耗時(shí): %llu ns", t);

警告:?

這里寫(xiě)的是我自己的理解,但是不一定正確,如果你有比較確切的資料或者不同的理解,麻煩告知我,萬(wàn)分感謝!?

dispatch_benchmark 應(yīng)該是通過(guò)計(jì)算多次執(zhí)行某代碼片段的總時(shí)間,通過(guò)多次運(yùn)行的總時(shí)間除以迭代運(yùn)行的次數(shù)來(lái)計(jì)算一次運(yùn)行的時(shí)間,以減小單次運(yùn)行的誤差。?

dispatch_benchmark(size_t count, void (^block)(void))返回的就是單次運(yùn)行代碼段的時(shí)間。

關(guān)于dispatch_benchmark1的更多的文章,我們可以去文章末的資料中查看。

區(qū)別

1、它們所屬的框架不同。

NSDate 來(lái)自Foundation框架,只需要#import,就可以使用了。CFAbsoluteTimeGetCurrent 來(lái)自CoreFoundation框架,而Foundation框架是包含CoreFoundation框架的。

CACurrentMediaTime 來(lái)自QuartzCore框架,而UIKit框架是包含了QuartzCore框架的。

dispatch_benchmark 來(lái)自?libdispatch(G C D)庫(kù),而Foundation框架已包含了libdispatch庫(kù)。

2、參考時(shí)間不同。?

NSDate 和 CFAbsoluteTimeGetCurrent 是通過(guò)ReferenceDate來(lái)計(jì)算相差的秒值。與服務(wù)器的時(shí)間有關(guān)系。?

而CACurrentMediaTime() 是封裝的mach_absolute_time(),mach_absolute_time() 是基于內(nèi)建時(shí)鐘的,能夠更精確更原子化地測(cè)量,并且不會(huì)因?yàn)橥獠繒r(shí)間變化而變化(例如時(shí)區(qū)變化、夏時(shí)制、秒突變等)。?

dispatch_benchmark的時(shí)間計(jì)算方式未知(推測(cè)不是根據(jù)參考時(shí)間計(jì)算)。

3、時(shí)間的精度不同?

NSDate、CFAbsoluteTimeGetCurrent、CACurrentMediaTime計(jì)算出來(lái)的時(shí)間精度都是秒。?

而dispatch_benchmark 的時(shí)間精度是納秒。

最后提醒

因?yàn)閺牟僮飨到y(tǒng)本身的一切基本因素都是可變性非常強(qiáng)的,性能應(yīng)該通過(guò)大量的試驗(yàn)來(lái)測(cè)量。對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō),樣本數(shù)量在 105?到 108?之間是合理的。?

所以我們應(yīng)該運(yùn)行要執(zhí)行的代碼段 105?到 108次,再來(lái)求平均值。

更多關(guān)于dispatch_benchmark的介紹。?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容