最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C++性能優(yōu)化大局觀

2023-07-05 13:16 作者:Boolan博覽  | 我要投稿

C++ 可算是一種聲名在外的編程語言了。這個名聲有好有壞。從好的方面講,C++ 性能非常好,哪個編程語言性能好的話總?cè)滩蛔∫?C++ 來單挑一下。從壞的方面講,它是臭名昭著的復(fù)雜、難學(xué)、難用。

不管說 C++ 是好還是壞,不可否認(rèn)的是,C++ 仍然是一門非常流行且非常具有活力的語言。繼沉寂了十多年后發(fā)布語言標(biāo)準(zhǔn)的第二版——C++11——之后,C++ 以每三年一版的頻度發(fā)布著新的語言標(biāo)準(zhǔn),每一版都在基本保留向后兼容性的同時提供著改進和新功能。

雖然在語言領(lǐng)域,也有Rust這樣的新語言在向 C++ 發(fā)起挑戰(zhàn),但是,不可否認(rèn)的是,C++ 仍然是面向性能的領(lǐng)域里的編程語言王者。我甚至不認(rèn)為 C++ 在性能方面次于 C——在極致追求速度時,C++ 可以比 C 更強,而 C 相比 C++ 的主要優(yōu)點是更加簡單:不管是學(xué)習(xí)、使用,還是產(chǎn)生的二進制代碼的體積上。

今天,我們就來大略討論一下,C++ 是如何做到高性能的。

Bjarne 老爺子認(rèn)為 C++ 最主要的特點在于以下兩方面的關(guān)注:

跟 C 語言一樣,C++ 提供非常底層的數(shù)據(jù)操作能力,為開發(fā)者提供了靈活性。跟“高級”語言一樣,C++ 提供了強大的抽象能力(可以說超越了大部分語言)。而且,相比 C,C++ 要安全得多。在語言誕生的初期就是如此,現(xiàn)在就更不用說了。

C++ 的類型系統(tǒng)比 C 更加嚴(yán)格,因此雖然一直有 C++ 是 C 的超集的說法,這個說法嚴(yán)格來說從來就沒成立過。最近(2023 年)碰到過一個程序崩潰的案例,簡化來講,就是開發(fā)者使用了一個 char 的二維數(shù)組(char names[MAX_NAMES]?[MAX_NAME_LEN]),然后把它傳給了一個接收 char**?參數(shù)的函數(shù)……這代碼當(dāng)然是錯的,但 C 編譯器雖然給了個告警,但編譯還是沒有失敗。如果這是 C++ 代碼的話,那編譯器就會直接報告錯誤,不給通過了。

而第二點,零開銷抽象,對于 C++ 的性能至關(guān)重要。我們有很多的抽象機制,同時,使用這些抽象機制并不會帶來額外的開銷。在某些情況下,使用這些機制,反而有“負(fù)開銷”—— “使用者”可以非常安全地使用這門語言,即可獲得極高的性能。同時,C++ 還給予 了“定制者”根據(jù)自己的需求來寫出更貼近使用場景的庫的能力,可以進一步方便“使用者”。

當(dāng)然,定制對程序員的技能有非常高的要求。初學(xué) C++ 的更需要掌握 C++ 的標(biāo)準(zhǔn)庫的使用——用好標(biāo)準(zhǔn)庫,就能獲得非常不錯的性能。正如高德納大神的名言的完整版:

就在同一篇論文的同一頁上,高德納還寫下了:

而 C++ 已經(jīng)提供相當(dāng)多的機制,可以允許我們很容易地獲取高性能,在很多場景下遠(yuǎn)遠(yuǎn)超過高德納所說的 12%。

我經(jīng)常舉的一個例子是 C++ 標(biāo)準(zhǔn)庫的sort和 C 標(biāo)準(zhǔn)庫的qsort:在關(guān)閉優(yōu)化時,我在某一測試場景下得到了 1:2.5 的性能差異,C++ 似乎要慢不少;但一旦打開 -O2(允許內(nèi)聯(lián))時,兩者的性能差異突變成 3.5:1,C++ 的性能比 C 高出了好幾倍!這就是所謂的“負(fù)開銷”了。C++ 的代碼比 C 的更簡單、更直觀,性能還更高。原因自然就是 C++ 的函數(shù)對象和模板機制允許編譯器更好地進行內(nèi)聯(lián),從而產(chǎn)生更加高性能的代碼。

因此,學(xué)會用好?C++ 的第一步是用好 C++ 的基本機制和標(biāo)準(zhǔn)庫,了解標(biāo)準(zhǔn)庫的不同機制的性能開銷,包括時間和空間。

任何情況下學(xué)習(xí) C++,第一需要了解的就是析構(gòu)函數(shù)和 RAII(resource acquisition is initialization)慣用法。對,雖然 C++ 誕生時名字是“帶類的 C”,但類和面向?qū)ο蟛⒉坏韧瑢γ嫦驅(qū)ο缶幊痰闹С植⒉皇?C++ 的最重要特性。C++ 的自定義類型的最特別之處不在多態(tài),而在對其行為的定制上——最重要的就是對象銷毀時應(yīng)該做些什么。析構(gòu)函數(shù)和析構(gòu)函數(shù)帶來的 RAII 慣用法,是 C++ 里最重要的特性,也是用 C++ 進行資源管理的關(guān)鍵。

重載是另外一個非常重要的 C++ 特性。除了你不用在名字上區(qū)分 process_char、process_string、process_int?帶來的方便性外,它對泛型編程也很重要,還對現(xiàn)代 C++ 的一個基本特性“移動語義”非常重要。刨除語法上的細(xì)節(jié),本質(zhì)上來說,移動語義就是讓程序員可以方便地區(qū)分會繼續(xù)使用的對象和以后不再使用的對象,允許對后者使用構(gòu)造函數(shù)和賦值運算符的重載來“竊取”其中的資源。對于一個普通的 vector,拷貝的開銷是 O(n)?或更高(如果 vector?成員是容器或其他具有高拷貝開銷的對象),但移動開銷通常(是,只是通常;不過通常你也不會遇到這種例外的特殊情況)是 O(1),常數(shù)復(fù)雜度。這就是我們在 C++ 里高效傳遞對象的一種常見方式了。

C++ 標(biāo)準(zhǔn)庫里最常用的組件恐怕就是 string?和各種容器了。它們都對移動進行了優(yōu)化。當(dāng)然,除了這個基本的性能點外,容器都有各自的特殊性能點,比如不同情況下的插入性能差異。這些都是需要學(xué)習(xí)的地方。

比如,vector?在尾部插入性能比較好,在中間插入性能比較差。不過,更進一步的是,你需要知道,尾部插入性能好的前提條件是元素的類型對移動有很好的實現(xiàn),并且移動構(gòu)造函數(shù)聲明成了 noexcept!如果你實現(xiàn)了開銷為 O(1) 的移動構(gòu)造函數(shù),但忘了把它聲明為 noexcept,那仍然是白搭,vector?的尾部插入仍然有性能問題。

又如,list?不管從開頭、結(jié)尾還是中間插入,都具有很高的性能。但是,對于相同元素的 list?和 vector,list?的遍歷性能可能要差一個數(shù)量級。這個原因就不完全是 C++ 的知識點了,而是跟硬件的緩存組織相關(guān)。如果我們關(guān)心性能的話,這些都是需要了解的地方。

前面我們已經(jīng)提到過模板,而 string?和容器也都是模板,行為可以通過模板參數(shù)來進行定制,并允許高效的內(nèi)聯(lián)優(yōu)化。模板當(dāng)然是 C++ 里比較復(fù)雜的一個地方,但基本的使用則相當(dāng)簡單:vector?就是一個放 int?的 vector,用起來跟一個普通的類沒有區(qū)別——只是模板創(chuàng)建者的工作簡單多了,不需要手工為不同的類型創(chuàng)建不同的類。

用好 C++、在項目中獲得令人滿意的性能 當(dāng)然不止上面這一些。最基本的,我們還需要了解標(biāo)準(zhǔn)庫算法,并合適地使用并發(fā)和并行來充分利用硬件。在本文中我們暫且就不展開了。

當(dāng)我們用熟了 C++ 之后,慢慢地,我們就會不再滿足于 C++ 標(biāo)準(zhǔn)庫這一“制式武器”。我們會尋找適合自己的第三方庫,甚至自己造輪子來滿足項目的特定需求。此時,我們就需要進一步了解 C++ 的高級特性。我們需要了解模板的進一步細(xì)節(jié),尤其是特化。我們需要了解 SFINAE 和模板元編程。我們需要了解 constexpr 和它帶來更方便的編譯期編程。C++ 的使用者也許可以暫時不關(guān)心這些問題,但定制者,或者說項目里的框架搭建者和工具提供者,必須去了解 C++?的這些高級特性,為你的項目提供扎實的基礎(chǔ)。

舉個例子,C++ 的標(biāo)準(zhǔn)庫提供了 list,雙向鏈表。這個庫沒啥問題,但在某些使用場景下,它的時間和空間開銷都不令人滿意,比如我們的對象除了正常的管理,還需要一個額外的 LRU(least recently used)算法來拋棄其中最老的項。你當(dāng)然可以使用 list,但每次插入操作都需要插入一個對象,除了有堆內(nèi)存分配開銷,你還需要考慮在這個 list?里到底存什么。也許用智能指針?情況是不是越搞越復(fù)雜了?

這種情況下,最合理的選擇是使用某種 intrusive_list,侵入式的鏈表,不需要在每次插入或刪除時進行內(nèi)存管理。C++ 標(biāo)準(zhǔn)庫沒有提供這個功能。你可以使用 Boost 里提供的容器,或者自己寫一個新的。對于這個例子,Boost 多半就足夠好了。但總可能出現(xiàn)一些現(xiàn)成庫解決不了的問題的,這時候,利用 C++ 的高級特性來自己造輪子就是一件非常自然的事。我們可以做到既有合適的定制,同時用法又跟已有的容器相似,沒有額外的學(xué)習(xí)成本。

或者,也許你希望使用分配器來創(chuàng)建一個容器內(nèi)存池,來提供對內(nèi)存的使用效率。這在 C++ 里也是非常容易完成的,只要你了解合適的定制機制。根據(jù)洋蔥原則,你可以不管這些定制點,直接用 C++,這樣最簡單;也可以把標(biāo)準(zhǔn)庫“切開”,以自己最喜歡的方式來拼接定制使用——當(dāng)然,這種做法確實跟切洋蔥一樣,很容易就會哭鼻子的。但它確實能幫助你獲得最高的可能性能

當(dāng)然,關(guān)于性能,該討論的還遠(yuǎn)遠(yuǎn)不止上面這些。有些話題跟 C++ 有關(guān)系,有些則跟硬件相關(guān),有些是通用的軟件問題,跟語言無關(guān)。目前我們只是管中窺豹,淺淺地進行了一些初步的探討。如果有興趣的話,歡迎來參加我的 C++ 性能優(yōu)化培訓(xùn)課程,對這些問題進行更加深入的探討。

課程介紹

C++,作為一門多范式的通用編程語言,適用的領(lǐng)域非常廣泛。要對C++程序進行性能優(yōu)化,牽涉到的方方面面也非常多。本課程就是以現(xiàn)代C+ +程序為中心,討論如何對C++程序進行優(yōu)化。課程中有跟語言強相關(guān)的內(nèi)容,也有跟語言關(guān)系較少、但在實踐中經(jīng)常伴隨C+ +程序出現(xiàn)的問題

課程收獲

名企好評

吳詠煒老師的《C++性能優(yōu)化高端培訓(xùn)》課程是 Boolan技術(shù)賦能培訓(xùn)的品牌課程,在華為、博世西門子、銀科、大疆等很多著名企業(yè)內(nèi)訓(xùn)都獲得高度認(rèn)可,得到參訓(xùn)學(xué)員一致好評


C++性能優(yōu)化大局觀的評論 (共 條)

分享到微博請遵守國家法律
佛山市| 彭泽县| 荥阳市| 昆明市| 开封市| 布拖县| 永丰县| 娄底市| 洪泽县| 乌鲁木齐市| 隆昌县| 潜山县| 临清市| 孟州市| 库尔勒市| 天气| 疏勒县| 平邑县| 拉萨市| 江源县| 杂多县| 尖扎县| 阳山县| 石泉县| 和田县| 鹿邑县| 阿克苏市| 普宁市| 疏附县| 蒙阴县| 潞西市| 溆浦县| 恩施市| 花莲县| 隆子县| 如东县| 海宁市| 定陶县| 龙陵县| 阳西县| 西贡区|