背景
在我們編程的時(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)求平均值。