今天在閱讀YYKit源碼(https://github.com/ibireme/YYKit.git)時發現在YYKitMacro.h組件中大量使用的內聯函數,例如此文件中的一個函數
static inline void dispatch_async_on_main_queue(void (^block)()) { if (pthread_main_np()) { block(); } else { dispatch_async(dispatch_get_main_queue(), block); } }
使用這個函數
dispatch_async_on_main_queue(^{
});
比如下我們經常使用起來更加簡潔:
dispatch_async(dispatch_get_main_queue(), ^{
});
那么再次使用內聯函數有什么好處呢?先說什么是內聯函數,課本上的定義:內聯函數是指用inline關鍵字修飾的函數。內聯函數不是在調用時發生控制轉移,而是在編譯時將函數體嵌入在每一個調用處。編譯時,類似宏替換,使用函數體替換調用處的函數名。C語言原本是不支持inline的,但C++中原生對inline的支持讓很多C編譯器也為C語言實現了一些支持inline語義的擴展。C99將inline正式放入到標准C語言中,並提供了inline關鍵字。和C++中的inline一樣,C99的inline也是對編譯器的一個提示,提示編譯器盡量按照內聯函數的定義去編譯,去除函數調用帶來的開銷。
C中引入inline關鍵字的原因:
inline 關鍵字用來定義一個類的內聯函數,引入它的主要原因是用它替代C中表達式形式的宏定義。
表達式形式的宏定義一例:
#define ExpressionName(Var1,Var2) (Var1+Var2)*(Var1-Var2)
為什么要取代這種形式呢,且聽我道來:
1.首先談一下在C中使用這種形式宏定義的原因,C語言是一個效率很高的語言,這種宏定義在形式及使用上像一個函數,但它使用預處理器實現,沒有了參數壓棧,代碼生成等一系列的操作,因此,效率很高,這是它在C中被使用的一個主要原因。
2.這種宏定義在形式上類似於一個函數,但在使用它時,僅僅只是做預處理器符號表中的簡單替換,因此它不能進行 參數有效性的檢測,也就不能享受C編譯器嚴格類型檢查的好處,另外它的返回值也不能被強制轉換為可轉換的合適的類型,這樣,它的使用就存在着一系列的 隱患和局限性。
3.在C中引入了類及類的訪問控制,這樣,如果一個操作或者說一個表達式涉及到類的保護成員或私有成員,你就不可能使用這種宏定義來實現。
4. inline 推出的目的,也正是為了取代這種表達式形式的宏定義,它消除了它的缺點,同時又很好地繼承了它的優點。
在使用inline函數要注意
1、你可以使用inline函數完全取代表達式形式的宏定義。
2、內聯函數一般只會用在函數內容非常簡單的時候,這是因為,內聯函數的代碼會在任何調用它的地方展開,如果函數太復雜,代碼膨脹帶來的惡果很可能會大於效率的提高帶來的益處。
3、在內聯函數內不允許用循環語句和 開關語句。 如果內聯函數有這些語句,則編譯將該函數視同普通函數那樣產生函數調用代碼,遞歸函數(自己調用自己的函數)是不能被用來做內聯函數的。內聯 函數只適合於只有1~5行的小函數。對一個含有許多語句的大函數,函數調用和返回的開銷相對來說微不足道,所以也沒有必要用內聯函數實現。
既然上面說使用內聯函數效率會提高,所以我簡單的謝了代碼驗證下
測試代碼如下:
static inline void add(int x, int y); int main(int argc, const char * argv[]) { clock_t start, finish; double duration; start = clock(); for (int i =0,j =0; i<100000; i++,j++) { add(i,j); } finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%f seconds\n", duration ); return 0; } void add(int x, int y) { int k = x+y; printf("%d\n",k); }
連續運行三次打印的結果是:
0.086523 seconds
0.086504 seconds
0.085425 seconds
然后把內聯函數改為普通函數再運行三次
void add(int x, int y); int main(int argc, const char * argv[]) { clock_t start, finish; double duration; start = clock(); for (int i =0,j =0; i<100000; i++,j++) { add(i,j); } finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%f seconds\n", duration ); return 0; } void add(int x, int y) { int k = x+y; printf("%d\n",k); }
打印結果:
0.085639 seconds
0.086934 seconds
0.085713 seconds
從結果可以看出,在本測試代碼中使用內聯函數確實能提高運行速度。所以我們以后可以在項目中適度使用內聯函數來提高APP性能。