圖書信息
傳世經典書叢
提高C++性能的編程技術[美]Dov Bulka(多夫·布爾卡) David Mayhew(大衛·梅休)著
左飛 薛佟佟 高陽 譯
ISBN 978-7-121- 12937-7
2011年3月出版
定價:59.00元
16開
292 頁
宣傳語
傳承大師智慧 領悟技術本真
經典名著 翻譯良品 典藏不二之選
內 容 簡 介
很多程式設計師及軟體設計師都認為,用C++開發意味著放棄程式性能提升的可能。在很多人眼裡,使用C++來開發那些效率至上的套用無疑將導致一場空前的浩劫。因此,在許多性能敏感型領域,諸如網路協定、作業系統核心、移動設備驅動等等,C++都常常處於被冷落的境地。
而本書正是對這種錯誤觀念的最有力回擊。本書揭示了C++開發高效套用的潛力,向廣大讀者展示了大量實用的C++面向對象編程技術。通過改善普遍藏匿於設計編碼過程暗處的缺陷,這些技術無一不為C++的性能提升帶來最為強勁的動力。
本書詳細討論了臨時對象、記憶體管理、繼承、虛函式、內聯、引用計數以及STL等一切有可能提升C++效率的細節內容。最終,該書將C++性能提升的各種終極利器,完美地呈現在廣大讀者的面前!無論你是相關領域的從業人員,還是C++程式設計愛好者,或者是渴望突破編程瓶頸、大幅提升自我修為的程式設計愛好者,本書都必將使你獲益良多。
作者簡介
Dov Bulka在軟體開發以及向市場交付大型軟體產品方面擁有超過15年的實戰經驗。他曾是IBM DominoGo Web伺服器的性能設計師,一些曾出現在Internet上的最大型網站使用了這種伺服器,其中包括1996年亞特蘭大奧運會的網站。Dov Bulka在杜克大學獲得了計算機科學博士學位。
David Mayhew是StarBridge Technologies,Inc.的首席設計師。他主要從事互連構造、對等處理和PCI匯流排研發等方面的工作,他曾就職於IBM的網路軟體部。David Mayhew在維吉尼亞理工大學獲得了計算機科學博士學位。
譯者簡介
左飛,技術作家、譯者。著有《C語言參悟之旅》 《C++數據結構原理與經典問題求解》 《數字圖像處理原理與實踐:基於Visual C++實現》 《代碼揭秘》等書。他在CSDN學生大本營上開設的主頁非常受歡迎,多篇關於程式設計學習的系列文章在網路上廣為流傳。
薛佟佟,研究興趣主要集中在無線感測網與分散式系統等領域,參與了多項國防基金項目的研究攻關。曾和左飛合作翻譯了Charles Petzold的名作《編碼——隱匿在計算機軟硬體背後的語言》。
中文版前言
在歲末年初、萬象更新之際,電子工業出版社隆重推出了引進版圖書大系——《傳世經典書叢》,而我們有幸參與了這項浩繁而極富意義的工作。作為該系列中的一員,《提高C++性能的編程技術》(Efficient C++: Performance Programming Techniques)是一本指導C++程式設計師如何寫出高性能程式的經典書籍,曾暢銷歐美,可以說是一本不折不扣的經典之作。
該書的兩位作者Dov Bulka和David Mayhew擁有豐富的實踐經驗和深厚的編程功底,他們將自己工作與學習中的寶貴經驗,匯聚成本書,旨在告訴人們這樣一個長期被忽略的事實——C++也能寫出高效的程式!這對長久以來存在於很多程式設計師和軟體設計師腦中的一種“偏見”構成了極大的挑戰,人們總是習慣於認為C++天生與高效就是對立的。Dov Bulka和David Mayhew所寫的這本書成功地否定了這一觀點。
Dov Bulka曾經在杜克大學獲得計算機科學博士學位,他在軟體開發以及向市場交付大型軟體產品方面擁有超過15年的經驗。他還曾經是IBM DominoGo Web伺服器的性能設計師。David Mayhew在維吉尼亞理工大學獲得計算機科學博士學位,並曾擔任StarBridge Technologies的首席設計師。由於兩位作者在商業應用程式開發中對於最佳性能方面的積極探索與實踐,掌握了第一手資料,他們藉由本書說明了C++在開發高效程式方面的潛力,同時提出了在實際開發中獲得大幅度性能提升的C++編程技術。本書重點討論C++開發中程式性能與可移植能力的提升,通過各種高效技術及精確測控,本書證明C++在這兩方面都可以臻於完美。另外,本書詳細討論了臨時對象、記憶體管理、繼承、虛函式、內聯、引用計數以及STL等一切有可能提升C++效率的細節內容。本書還指出了在設計和編碼中產生隱含操作代價的一些常見錯誤。
通過本書,讀者可以了解C++程式設計中關於性能提升的主要技術。因此,本書對於渴望提高C++程式性能的讀者來說將大有裨益,而且更重要的是,讀者通過本書可以更深入地探討C++高級程式設計思路與方法。
參與本書翻譯工作的還有南京航空航天大學計算機科學與技術學院研究生宋通、劉彧、張銳恆和殷科科。他們的謙遜與協作精神,以及對於學術問題的孜孜以求和紮實的技術功底都給我們留下了深刻的印象。在此對他們的辛勤付出表示最誠摯的謝意!
電腦程式設計其實是一門妙不可言的藝術。但是真正能將自己從埋頭苦幹的工匠變成收放自如的設計師,領會程式設計之美,卻非易事。無論何時,在使自己變得更加優秀的過程中,一本好書的作用永遠不能被忽視!筆者真誠地希望本書能夠在這個過程中幫到各位讀者。為此,我們始終以審慎、嚴謹的態度對待此書的翻譯工作,力求最大程度地貼合中國讀者的閱讀習慣,並且不喪失原作的風采。然而,翻譯和出版終究是留有缺憾的藝術,紕漏和欠缺往往在所難免,我們真誠地希望廣大讀者朋友不吝賜教與指正,這將成為我們將此書不斷完善的最強大動力
譯 者
2010年冬
序 言
如果就C++的性能問題對軟體開發者進行一次非正式調查,您會毫無疑問地發現,他們中絕大多數人把性能問題視為C++語言相較於其他優秀語言的阿特琉斯之踵。自從C++誕生以來,我們多次聽到這樣的話:開發性能要求嚴格的程式儘量不選擇C++。在開發人員看來,編寫這一類的程式首選的語言通常是標準C,有時甚至是彙編語言。
作為軟體社區的一分子,我們有機會目睹了這種神話般語言的發展和壯大。幾年前,我們充滿熱情地加入了投入C++懷抱的浪潮中,我們身邊的許多開發項目也都很積極地投身於其中。一段時間過後,以C++實現的軟體解決方案開始發生變動。人們發現C++的性能不太理想,所以就逐漸放棄了它。在對性能要求嚴格的領域,人們對於C++的熱情冷卻了下來。當時我們正在為別人提供網路軟體,這些軟體的運行速度是不容協商的,也就是說速度必須放在第一位。由於網路軟體位於軟體層級鏈中相對低的層次,而且大量的應用程式位於網路軟體之上並且依賴於它,所以網路軟體的性能要求比較嚴格。較低層級鏈上的程式性能不佳會對較高層級鏈上的程式產生影響。
並不是我們才有這樣的經驗。在我們周圍,不少骨灰級的C++使用者也很難用C++取得他們所期盼的性能。沒有人認為問題在於面向對象開發模式有多難學,反而怪罪C++語言本身。儘管C++編譯器本質上還處於“嬰兒期”,但C++語言已經被打上了“天生就慢”的標籤。這種看法迅速傳播並被廣泛地當做事實接受。不使用C++的軟體企業經常說他們這么做是因為性能是他們考慮的主要因素。這種考慮源於人們認為C++語言無法達到與之相對的C語言所達到的性能。因此,C++很少在一些對性能要求很嚴格的軟體領域取得成功,如作業系統核心、設備驅動程式、網路系統(路由器、網關、協定棧)等。
我們花費了很多年時間用來剖析用C和C++代碼寫成的大型系統,以充分發揮這些代碼的性能。在整個過程中我們竭盡全力尋找用C++產生高效程式的潛力。我們發現事實上C++確實是有這個潛力的。在本書中,我們試著與您分享這些經歷,以及在剖析C++效率的過程中所得到的一些經驗教訓。編寫高效的C++代碼,並非輕而易舉,也不是比登天還難。要做到這一點,需要理解性能規律,以及掌握一些有關C++性能陷阱和缺陷的知識。
80-20法則是軟體結構領域的一個重要原則。在本書的寫作中我們同樣認同它的存在:20%的性能缺陷將會占用我們80%的時間。因此我們把精力集中在最有價值的地方。我們主要對那些經常在工業化代碼中出現,並有顯著影響的性能問題進行剖析。本書不對各種可能出現的性能缺陷及其解決方法進行詳盡的討論,因此,將不討論我們認為深奧而不常見的性能缺陷。
毫無疑問,我們的觀點來自於我們作為程式設計師在開發伺服器端、對性能要求嚴格的通信程式中獲取的實際經驗。由此形成的觀點會在以下方面影響本書:
在實踐中所遇到性能問題與在科學計算、資料庫程式和其他領域中所遇問題在本質上稍有不同。這沒什麼大不了的。普遍的性能原則適用於各個領域(包括在網路軟體以外的領域)。
儘管我們儘量避免,但有時候還是會人為地虛構一些例子來佐證一些觀點。以前我們犯過足夠多的編碼錯誤,所以能提供足夠多的來自於我們所編寫的真實的產品代碼中的例子。我們的經驗得來不易——是從自己和同事所犯的錯誤中學習而來的。我們將儘可能使用實際範例來證明我們的觀點。
我們將不對算法漸近複雜性、數據結構,以及數據的訪問、排序、搜尋及壓縮的最新和最優技術進行深入的研究。這些確實是重要的論題,但是其他地方已給出大量的論述[Knu73、BR95、KP74]。我們將著重論述那些簡單、實用、常見的、會大幅提高性能的編碼和設計原則。也許您在不知情的狀態下使用了會導致隱含性高消耗的語言特性,也許您違反了敏感(或是不太敏感)的性能原則,這些會導致性能降低的常見的設計和編碼方法,我們都將一一指出。
我們如何區分傳說與現實呢?C++的性能真的比C語言的要差么?筆者認為人們通常所持的C++性能差的觀點是不正確的。確實,在一般情況下,如果把C語言和看起來與C語言相同的C++版本相比,前者通常要快一些。但同時筆者也認為兩種語言在表面上的相似性通常是基於它們的數據處理功能,而不是它們的正確性、健壯性和易維護性。我們的觀點是如果讓C語言程式在上述方面達到C++程式的級別,則速度差別就會消失,甚至可能是C++版本的程式更快。
C++不是天生就較慢或較快,這兩者都是有可能的,關鍵要看怎樣使用它以及想從它那裡得到什麼。這與如何使用C++有關係:運用得當的話,C++不僅可以讓軟體系統具備可接受的性能,甚至還可以獲得出眾的性能。
在此我們向那些對本書做出過貢獻的人表示感謝。萬事開頭難,我們的編輯Marina Lang對本書寫作項目的啟動給予了幫助。Julia SIME為早期的書稿做出了不小的貢獻,Yomtov Meged也給我們提供了很多有價值的建議。他還指出了我們的想法與客觀情況之間的細微差別。儘管有時它們碰巧會一致,但對我們而言還是有必要加以區分的。
十分感謝Addison-Wesley聘請的兩位評審,他們的反饋信息非常有價值。
同時感謝對原稿進行了檢查的朋友和同事,他們是(排名不分先後):Cyndy Ross、Art Francis、Scott Snyder、Tricia York、Michael Fraenkel、Carol Jones、Heather Kreger、Kathryn Britton、Ruth Willenborg、David Wisler、Bala Rajaraman、Don “Spike” Washburn和Nils Brubaker。
最後但並非最不重要,還要感謝我們各自的妻子:Cynthia Powers Bulka和Ruth Washington Mayhew。
Dov Bulka
David Mayhew
目 錄
導讀 1
第1章 跟蹤實例 10
1.1 初步跟蹤的實現 12
1.2 要點 18
第2章 構造函式和析構函式 20
2.1 繼承 20
2.2 複合 32
2.3 緩式構造 34
2.4 冗餘構造 37
2.5 要點 41
第3章 虛函式 43
3.1 虛函式的構造 43
3.2 模板和繼承 46
3.3 要點 51
第4章 返回值最佳化 52
4.1 按值返回機制 52
4.2 返回值最佳化 54
4.3 計算性構造函式 57
4.4 要點 58
第5章 臨時對象 59
5.1 對象定義 59
5.2 類型不匹配 60
5.3 按值傳遞 63
5.4 按值返回 64
5.6 使用op=()消除臨時對象 66
5.7 要點 67
第6章 單執行緒記憶體池 69
6.1 版本0:全局函式new()和delete() 70
6.2 版本1:專用Rational記憶體管理器 71
6.3 版本2:固定大小對象的記憶體池 76
6.4 版本3:單執行緒可變大小記憶體管理器 80
6.5 要點 87
第7章 多執行緒記憶體池 88
7.1 版本4:實現 88
7.2 版本5:快速鎖定 91
7.3 要點 95
第8章 內聯基礎 96
8.1 什麼是內聯? 96
8.2 方法調用的代價 100
8.3 因何內聯? 105
8.4 內聯詳述 105
8.5 虛方法的內聯 107
8.6 通過內聯提升性能 108
8.7 要點 109
第9章 內聯——站在性能的角度 110
9.1 調用間最佳化 110
9.2 何時避免內聯? 115
9.3 開發階段及編譯期的內聯考慮 118
9.4 基於配置的內聯 119
9.5 內聯規則 123
9.6 要點 125
第10章 內聯技巧 126
10.1 條件內聯 126
10.2 選擇性內聯 127
10.3 遞歸內聯 129
10.4 對靜態局部變數進行內聯 134
10.5 與體系結構有關的注意事項:多暫存器集 136
10.6 要點 137
第11章 標準模板庫 138
11.1 漸近複雜度 138
11.2 插入 139
11.3 刪除 146
11.4 遍歷 149
11.5 查找 150
11.6 函式對象 152
11.7 比STL更好? 154
11.8 要點 157
第12章 引用計數 158
12.1 實現細節 160
12.2 已存在的類 172
12.3 並發引用計數 175
12.4 要點 179
第13章 編碼最佳化 180
13.1 快取 182
13.2 預先計算 183
13.3 降低靈活性 184
13.4 80-20法則:加快常用路徑的速度 185
13.5 延遲計算 189
13.6 無用計算 191
13.7 系統體系結構 192
13.8 記憶體管理 193
13.9 庫和系統調用 194
13.10 編譯器最佳化 197
13.11 要點 198
第14章 設計最佳化 200
14.1 設計靈活性 200
14.2 快取 204
14.3 高效的數據結構 208
14.4 延遲計算 208
14.5 getpeername() 209
14.6 無用計算 212
14.7 失效代碼 213
14.8 要點 214
第15章 可擴展性 215
15.1 對稱多處理器架構 217
15.2 Amdahl定律 218
15.3 多執行緒和同步 220
15.4 將任務分解為多個子任務 221
15.5 快取共享數據 222
15.6 無共享 224
15.7 部分共享 226
15.8 鎖粒度 228
15.9 偽共享 230
15.10 驚群現象 231
15.11 讀/寫鎖 233
15.12 要點 234
第16章 系統體系結構相關話題 235
16.1 存儲器層級 235
16.2 暫存器:存儲器之王 237
16.3 磁碟和記憶體結構 241
16.4 快取效應 244
16.5 快取抖動 246
16.6 避免跳轉 247
16.7 使用簡單計算代替小分支 248
16.8 執行緒化的影響 249
16.9 上下文切換 251
16.10 核心交叉 254
16.11 執行緒化選擇 255
16.12 要點 257
參考文獻 258
索引 260