Objective-C 中如何測量代碼的效率

背景

在咱們編程的時候,可能常常會有一些疑問:macos

  • 咱們寫的某個方法的執行效率是多少?
  • 方法 A 和 方法 B 哪一個更快?

所以,咱們不可避免的要用到一些方法來計算代碼的執行效率。計算代碼的執行效率可使用的API有:編程

  • NSDate
  • CFAbsoluteTimeGetCurrent
  • CACurrentMediaTime
  • dispatch_benchmark

NSDate

看到NSDate,你們應該都能想到怎麼使用吧。爲了更直觀一點,我仍是使用代碼片斷來演示好了:bash

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

上面是一段 C與OC混合的代碼片斷,計算斐波那契數列計算第10個數的值須要消耗的時間。服務器

利用NSDate 來計算運行效率:代碼段運行前記錄一次時間,運行後記錄一次,而後比較時間差。 時間的單位是 框架

CFAbsoluteTimeGetCurrent

利用CFAbsoluteTimeGetCurrent 主要是利用CFAbsoluteTimeGetCurrent()函數來獲取當前的絕對時間。一樣的我也是用代碼片斷來演示:函數

CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
NSLog(@"斐波那契數:%d",fibonacci(10)) ;
CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
NSLog(@"耗時:%f",endTime - startTime);
複製代碼

利用CFAbsoluteTimeGetCurrent 來計算運行效率:代碼段運行前記錄一次時間,運行後記錄一次,而後比較時間差。 時間的單位是 性能

看到這裏可能會有疑問CFAbsoluteTimeGetCurrent()是如何獲取時間的呢? 咱們追蹤進去查看代碼,就會有答案了,這是源碼:ui

typedef double CFTimeInterval;
typedef CFTimeInterval CFAbsoluteTime;
/* absolute time is the time interval since the reference date */
/* the reference date (epoch) is 00:00:00 1 January 2001. */

CF_EXPORT
CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
複製代碼

CFTimeInterval的定義和註釋能夠看出,CFAbsoluteTimeGetCurrent(void)返回的時間就是當前時間相對與reference date的時間。spa

CFTimeInterval 是對double 的重命名。而NSTimeInterval 也是對double 的重命名。 它們之間的關係就可想而已了!操作系統

CFAbsoluteTimeGetCurrent() 其實等價於 [[NSDate new] timeIntervalSinceReferenceDate]

CACurrentMediaTime

利用CACurrentMediaTime主要是利用CACurrentMediaTime()函數來計算時間。 仍是先用示例來演示用法:

CFTimeInterval startTime = CACurrentMediaTime();
NSLog(@"斐波那契數:%d",fibonacci(10)) ;
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"耗時:%f",endTime - startTime);
複製代碼

計算執行效率時間上依然是:代碼段運行前記錄一次時間,運行後記錄一次,而後比較時間差。 時間的單位是

跟蹤查看源碼中對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() 是對mach_absolute_time()的封裝。返回的是CoreAnimation 中的當前時間。

dispatch_benchmark

dispatch_benchmark 是 libdispatch(Grand Central Dispatch) 的一部分。但嚴肅地說,這個方法並無被公開聲明,因此咱們必需要本身聲明:

extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));
複製代碼

第二個參數是執行的代碼片斷block。 第一個參數是執行的次數(即運行block 的次數)。

uint64_t t = dispatch_benchmark(1000000, ^{
    NSLog(@"斐波那契數:%d",fibonacci(10)) ;
  });
NSLog(@"耗時: %llu ns", t);
複製代碼

警告: 這裏寫的是我本身的理解,可是不必定正確,若是你有比較確切的資料或者不一樣的理解,麻煩告知我,萬分感謝! dispatch_benchmark 應該是經過計算屢次執行某代碼片斷的總時間,經過屢次運行的總時間除以迭代運行的次數來計算一次運行的時間,以減少單次運行的偏差。 dispatch_benchmark(size_t count, void (^block)(void))返回的就是單次運行代碼段的時間。

關於dispatch_benchmark[1]的更多的文章,咱們能夠去文章末的資料中查看。

區別

  • 一、它們所屬的框架不一樣。
NSDate 來自Foundation框架,只須要#import <Foundation/Foundation.h>,就可使用了。
CFAbsoluteTimeGetCurrent 來自CoreFoundation框架,而Foundation框架是包含CoreFoundation框架的。
CACurrentMediaTime 來自QuartzCore框架,而UIKit框架是包含了QuartzCore框架的。
dispatch_benchmark 來自 libdispatch(G C D)庫,而Foundation框架已包含了libdispatch庫。
複製代碼
  • 二、參考時間不一樣。 NSDate 和 CFAbsoluteTimeGetCurrent 是經過ReferenceDate來計算相差的秒值。與服務器的時間有關係。 而CACurrentMediaTime() 是封裝的mach_absolute_time(),mach_absolute_time() 是基於內建時鐘的,可以更精確更原子化地測量,而且不會由於外部時間變化而變化(例如時區變化、夏時制、秒突變等)。 dispatch_benchmark的時間計算方式未知(推測不是根據參考時間計算)。

  • 三、時間的精度不一樣 NSDate、CFAbsoluteTimeGetCurrent、CACurrentMediaTime計算出來的時間精度都是。 而dispatch_benchmark 的時間精度是納秒

最後提醒

由於從操做系統自己的一切基本因素都是可變性很是強的,性能應該經過大量的試驗來測量。對於大多數應用來講,樣本數量在 105 到 108 之間是合理的。 因此咱們應該運行要執行的代碼段 105 到 108次,再來求平均值。


  1. 更多關於dispatch_benchmark的介紹↩︎

相關文章
相關標籤/搜索