天天看點

《C語言接口與實作:建立可重用軟體的技術》一1.3 效率

本節書摘來自異步社群《c語言接口與實作:建立可重用軟體的技術》一書中的第1章,第1.3節,作者 傅道坤,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

程式員似乎被效率問題困擾着。他們可能花費數小時來微調代碼,使之運作得更快。遺憾的是,大部分這種工作都是無用功。當猜測程式的運作時間花費在何處時,程式員的直覺非常糟糕。

微調程式是為了使之更快,但通常總是會使之更大、更難了解、更可能包含錯誤。除非對執行時間的測量表明程式太慢,否則這樣的微調沒有意義。程式隻需要足夠快即可,不一定要盡可能快。

微調通常在“真空”中完成。如果一個程式太慢,找到其瓶頸的唯一途徑就是測量它。程式的瓶頸很少出現在預期位置或者是因你所懷疑的原因導緻,而且在錯誤位置上微調程式是沒有意義的。在找到正确的位置後,僅當該處花費的時間确實占運作時間的很大比例時,才有必要進行微調。如果i/o占了程式運作時間的60%,在搜尋例程中節省1%是無意義的。

微調通常會引入錯誤。最快崩潰的程式絕非勝者。可靠性比效率更重要;與傳遞足夠快的可靠軟體相比,傳遞快速但會崩潰的軟體,從長遠看來代價更高。

微調經常在錯誤的層次上進行。快速算法的直接簡明的實作,比慢速算法的手工微調實作要好得多。例如,減少線性查找的内層循環的指令數,注定不如直接使用二分查找。

微調無法修複低劣的設計。如果程式到處都慢,這種低效很可能是設計導緻的。當基于編寫得很糟糕或不精确的問題說明給出設計時,或者根本就沒有總體設計時,就會發生這種令人遺憾的情況。

本書中大部分代碼都使用了高效的算法,具有良好的平均情況性能,其最壞情形性能也易于概括。對大多數應用程式來說,這些代碼對典型輸入的執行時間總是足夠快速的。當某些程式的代碼性能可能會導緻問題時,書中自會明确注明。

一些c程式員在尋求提高效率的途徑時,大量使用宏和條件編譯。隻要有可能,本書将避免使用這兩種方法。使用宏來避免函數調用基本上是不必要的。僅當客觀的測量結果表明有問題的調用的開銷大大超出其餘代碼的運作時間時,使用宏才有意義。操作i/o是較适宜采用宏的少數情況之一。例如,标準的i/o函數getc、putc、getchar和putchar通常實作為宏。

條件編譯通常用于配置特定平台或環境的代碼,或者用于代碼調試的啟用/禁用。這些問題是實際存在的,但條件編譯通常隻是解決問題的較為容易的方法,而且總會使代碼更難于閱讀。而重寫代碼以便在執行期間選擇平台依賴關系通常則更為有用。例如,一個編譯器可以在執行時選擇多種(比如說6種)體系結構中的一個來生成代碼,這樣的一種交叉編譯器要比必須配置并搭建6個不同的編譯器更有用,而且可能更易于維護。

如果應用程式必須在編譯時配置,與c語言的條件編譯工具相比,版本控制工具更擅長完成該工作。這樣,代碼中就不必充斥着預處理器指令,因為那會使代碼難于閱讀,并模糊被編譯和未被編譯的代碼之間的界限。使用版本控制工具,你看到的代碼即為被執行的代碼。對于跟蹤性能改進情況來說,這些工具也是理想的選擇。

繼續閱讀