優化概述

優化概述

許多優化機會的出現源於某些C++特性被無用而致使程序運行緩慢、消耗許多資源,這些代碼雖然是正確的,卻不完善。這些代碼每每是由於開發人員缺少現代微處理器設備的基本常識,或是沒有仔細考慮各類C++對象構建方式的性能開銷而編寫出的。可進行優化的另一個緣由是,C++提供了對內存管理和複製的精準控制功能。算法

優化是軟件開發的一部分

優化是一項編碼活動。在傳統的軟件開發過程當中,直到編碼完成,項目進入了集成與測試階段,可以觀察到程序總體的性能時,纔會進行優化。而在敏捷開發方式中,當一個帶有性能指標的特性編碼完成後或是須要實現特定的性能目標時,就會分配一個或多個迭代進行優化。編程

Bug修復與性能優化之間的一個重要區別是,性能是一個連續變量。特性要麼是實現了,要麼是沒有實現;Bug要麼存在,要麼不存在。可是能夠是很是糟糕或者很是優秀,還多是介於這二者之間的某種程度。優化仍是一個迭代的過程,每當程序中最慢的部分被改善後,一個新的最慢的部分就會出現。緩存

與其餘編碼任務相比,優化更像是一門實驗科學,須要有更深刻的科學思惟方式。要想優化成功,須要先觀察程序行爲,而後基於這些程序行爲做出可測試的推測,再進行實驗得出測試結果。這些測試結果要麼驗證推測,要麼推翻推測。經驗豐富的開發人員經常相信他們對於最優代碼具備足夠的經驗和直覺。可是除非他們頻繁地測試本身的直覺,不然一般他們都是錯誤的。實驗,而非直覺,纔是貫穿本書的主題。安全

優化是高效的

開發人員很難理解單個編碼決策對大型程序的總體性能的影響。所以,實際上全部完整的程序都包含大量的優化機會。即便是經驗豐富的團隊在時間充裕的狀況下編寫出的代碼,運行速度一般也能夠提升 30%-100%。不過,經過微調代碼讓程序的運行速度提高10多倍幾乎是不可能的,選擇一種更好的算法或是數據結構,則能夠將程序的某個特性的性能從慢到沒法忍受提高至可發佈的狀態。性能優化

優化是沒有問題的

「不要進行優化」這條建議被過分推崇,我以爲不要過於教條,優化是沒有問題的。學習高效的編程慣用法是沒有問題的,即便你不知道哪部分代碼的性能很重要。當你擁有良好的編程習慣,編寫高效代碼與編寫低效無用的代碼所花的時間是同樣的,那爲何不優化呢?數據結構

可是,若是你不清楚重要性,由於不肯定哪一個算法更好而致使許多天過去了項目仍毫無進展,這是不行的。
不知道性能問題出在哪裏就花費不少時間進行優化,這是不行的。試圖修改程序中的每句語句去改善程序性能沒有必要,也不會有做用。只有10%的代碼會對程序的性能產生顯著的影響,那麼試圖隨機找出一個性能改善切入點的機率就會很低。如何使用工具定位代碼中的「熱點「就很重要。併發

實際上,常識多是性能改善最大的敵人。常識的「解毒劑」是實驗形式的科學方法。要學會利用工具測量軟件性能,並經過實驗驗證優化效果。函數

C++代碼優化策略總結

C++的混合特性爲咱們提供了多種實現方式,一方面能夠實現性能管理的全自動化,另外一方面也能夠對性能進行更加精準的控制。高併發

C++有一些熱點代碼是性能慣犯,其中包括函數調用、內存分配和循環。如下是一份改善C++程序性能的方法總結。工具

用好的編譯器並用好編譯器

使用支持C++11的編譯器。C++11實現了右值引用(rvalue reference)和移動語義(move semantics),能夠省去許多在之前的C++版本中沒法避免的複製操做。

打開編譯器的優化選項。

使用更好的算法

選擇一個最優算法對性能優化的效果最大。各類優化手段都能改善程序的性能,但大部分只能使程序性能呈線性提高。除非你能找到一個更加高效的算法,不然要想實現性能的指數級增加一般是不太可能的。

優化一個糟糕的算法很愚蠢。對代碼優化而言,學習和使用查找和排序的最優算法纔是康莊大道。替換一個更優的算法後,數據集越大,能夠縮短的運行時間就越多。

使用更好的庫

C++編譯器提供的標準C++模板庫和運行時庫必須是可維護的、全面的和很是健壯的。咱們無需對這些庫進行調優。雖然C++已經發明出來30年多了,商業C++編譯器的庫仍然有Bug,而且可能不遵循如今的C++標準,甚至不遵循編譯器發佈時的標準。這使得測量和推薦優化方法的任務變得很是複雜,也使得開發人員認爲沒有任何優化經驗是能夠移植的。

有一些開源庫實現了很是重要的功能,如內存管理。它們提供的複雜的實現可能比供應商提供的C++運行時庫更快、更強。這些可供選擇的開源庫的一個優點是,它們很容易地整合至現有的工程中,並可以當即改善程序性能。

最後,開發人員還能夠開發適合本身項目的庫,經過放鬆標準庫中的某些安全性和健壯性約束來換取更快的運行速度。

某些方式的函數調用的開銷很是大。優秀的函數庫的API所提供的函數反映了這些API的慣用法,使得用戶能夠無需頻繁地調用其中的基礎函數。

要想隱藏高度優化後的程序的複雜性,函數和類庫是很是適合的地方。做爲調用庫的回報,它們會以最高的效率完成工做。庫函數一般位於深層嵌套 調用鏈的底端,在那裏,性能改善的效果會更加明顯。

減小內存分配和複製

減小對內存管理器的調用是一種很是有效的優化手段,絕大多數C++語言特性的性能開銷最多隻是幾個指令,可是每次調用內存管理器的開銷倒是數千個指令。

字符串是許多C++程序中很是重要和性能開銷大的部分。

對緩存複製函數的一次調用也可能消耗數千個CPU週期。所以,減小複製是一種提升代碼運行速度的優化方式。大量複製的發送都與內存分配有關,因此修改一處每每也會消滅另外一處。其餘可能會發生複製的熱點代碼是構造函數和賦值運算符以及輸入輸出。

移除計算

除了內存分配和函數調用外,單條C++語句的性能開銷一般都很小。但若是在循環中執行了100萬次,或者每次處理時都執行這條語句,那麼這就是個大問題了。絕大多數程序都會有一個或多個主要的時間處理循環和一個或多個處理字符的函數。找出並優化這些循環。

在嘗試減小計算數量以前,肯定程序中哪部分會被頻繁地執行。

同時,現代C++編譯器在進行這些局部改善方面也作得很是優秀了。所以,不該當有強迫症,將i++都替換成++i,或是展開全部的循環,竭盡全力地向每位同時講解什麼是達夫設備以及它的優勢。

使用更好的數據結構

選擇最合適的數據結構對性能有着深入的影響,由於插入、迭代、排序和檢索元素的算法的運行時開銷取決於數據結構。除此以外,不一樣的數據結構在使用內存管理器的方式上也有所不一樣。另外一個緣由是數據結構可能有也可能沒有優秀的緩存本地化。

提升併發性

大多數程序都須要等待。任什麼時候候,若是一個程序的處理進度因須要等待這些時間被暫停,而沒有利用這些時間進行其餘處理,都是一種浪費。

現代計算機均可以使用多個處理核心來執行指令。若是一項工做被分給幾個處理器執行,那麼它能夠更快地執行完畢。

伴隨併發執行而來的是用於同步併發線程讓它們能夠共享數據的工具。

優化內存管理

內存管理器做爲C++運行時庫中的一部分,管理着動態內存分配。它在許多C++程序中都會被頻繁地執行。C++確實爲內存管理提供了豐富的API,雖然多數開發人員都歷來沒有使用過。

相關文章
相關標籤/搜索