⑴ 浠g爜榪愯屾晥鐜囨槸浠涔堟剰鎬濓紵
鍦ㄨ$畻鏈洪嗗煙涓錛屼唬鐮佽繍琛屾晥鐜囨槸鎸囩▼搴忓湪榪愯屾椂鎵鑺辮垂鐨勬椂闂村拰鍗犵敤鐨勮祫婧愩傝繖鍖呮嫭CPU鏃墮棿銆佸唴瀛樹嬌鐢ㄣ佸勭悊鍣ㄧ殑璐熻澆絳夋柟闈銆備竴涓楂樻晥鐨勭▼搴忚兘澶熷湪鏈鐭鏃墮棿鍐呭勭悊鏈澶氭暟鎹錛屽甫鏉ョ殑鏄鏇村揩鐨勫搷搴旀椂闂村拰鏇村ソ鐨勭敤鎴蜂綋楠屻傜劧鑰岋紝浠g爜榪愯屾晥鐜囧苟涓嶅彧鏄涓涓紼嬪簭鏈緇堟墽琛岀殑閫熷害錛屽畠涔熶笌緙栫爜瑙勮寖銆佺畻娉曡川閲忋佹爣鍑嗗簱絳夊洜緔犳湁鍏熾
楂樻晥鐨勭▼搴忓彲浠ュ甫鏉ユ樉钁楃殑濂藉勶紝濡傝妭鐪佹椂闂淬佽妭鐪佽祫婧愮瓑銆傚挨鍏舵槸鍦ㄥぇ瑙勬ā鏁版嵁澶勭悊鍜岄珮騫跺彂鍦烘櫙涓嬶紝浠g爜榪愯屾晥鐜囨垚涓轟簡涓涓蹇呴』瑕佽冭檻鐨勯棶棰樸備負浜嗘彁鍗囩▼搴忕殑鎬ц兘錛屽繀欏諱簡瑙e拰榪愮敤鍚堥傜殑綆楁硶緇撴瀯鍜屾暟鎹緇撴瀯錛岃勯伩涓浜涘彲鑳藉瓨鍦ㄧ殑璧勬簮嫻璐癸紝鍚屾椂涔熷彲浠ュ噺灝戜竴浜涜繍琛岀紦鎱㈢殑閿欒鎴栧穿婧冦傛彁楂樹唬鐮佽繍琛屾晥鐜囧彲浠ュ甫鏉ユ洿濂界殑璁$畻絝浣撻獙錛屼篃鍙浠ユ帹鍔ㄤ笟鍔″為暱銆
鎻愰珮浠g爜榪愯屾晥鐜囨槸涓涓澶嶆潅鐨勪換鍔★紝闇瑕佺患鍚堣冭檻緙栫▼鎶鏈銆佷唬鐮佽川閲忓拰閮ㄧ講鐜澧冪瓑鍥犵礌銆備互涓嬫槸鍑犵嶉氱敤鐨勬柟娉曪細
浼樺寲綆楁硶鍜屾暟鎹緇撴瀯錛屽敖鍙鑳戒嬌鐢ㄦ椂闂村嶆潅搴︿綆鐨勭畻娉曪紱
緙栧啓騫插噣鏉炬暎鐨勪唬鐮佸拰娉ㄩ噴錛屽彲浠ユ彁楂樹唬鐮佸彲緇存姢鎬у拰鍙璇繪э紱
閬垮厤浣跨敤榪囧氱殑寰鐜宓屽楀拰閲嶅嶈$畻絳夊姩浣滐紝鍙浠ュ噺灝戣祫婧愭氮璐癸紱
浣跨敤寮傛ョ紪紼嬨佺紦瀛樻暟鎹鍜屾噿鍔犺澆絳夋柟寮忓彲浠ュ噺灝慖O闃誨烇紱
浣跨敤閫傚綋鐨勭紪璇戦夐」銆佺▼搴忕粍浠跺拰閰嶇疆錛屽彲浠ヤ紭鍖栫紪璇戝拰閮ㄧ講銆
⑵ 影響vs編譯速度的因素有哪些
影響因素比較多:
1 文件的大小,文件大小指的是全部include展開後的大小。
2 文件數量,編譯是一個一個文件進行的,所以你的工程的文件數量也有關系。
3 還有聲明的復雜程度,復雜聲明需要額外地計算。
4 最影響編譯速度的估計是C++的模板,模板在編譯的時候要進行推導,得到相應的結果,這個非常費時間。如果你是模板里還套了模板,那就比較慢了。
5 鏈接庫的數量,鏈接很多庫也會使得編譯速度變慢。
6 inline函數展開,會使得代碼膨脹,也會影響編譯速度
7 debug模式編譯要留符號表做調試,也會影響速度
8 release模式如果開了優化,編譯優化會改變代碼的某些結構,這也是拖慢編譯器的一個重要因素。
⑶ 淺談怎樣加快C++代碼的編譯速度
首先一點 加快編譯速度意義不大。
需要整個項目重新編譯的情況並不多,而每次只修改若干文件的情況下,加快速度也不會有太大影響。
更重要的應該把目光放在加快運行速度上。
要加快編譯速度,可以從這幾個方面嘗試。
一、代碼角度
1、在頭文件中使用前置聲明,而不是直接包含頭文件。
不要以為你只是多加了一個頭文件,由於頭文件的"被包含"特性,這種效果可能會被無限放大。所以,要盡一切可能使頭文件精簡。很多時候前置申明某個namespace中的類會比較痛苦,而直接include會方便很多,千萬要抵制住這種誘惑;類的成員,函數參數等也盡量用引用,指針,為前置聲明創造條件。
2、使用Pimpl模式
Pimpl全稱為Private Implementation。傳統的C++的類的介面與實現是混淆在一起的,而Pimpl這種做法使得類的介面與實現得以完全分離。如此,只要類的公共介面保持不變,對類實現的修改始終只需編譯該cpp;同時,該類提供給外界的頭文件也會精簡許多。
3、高度模塊化
模塊化就是低耦合,就是盡可能的減少相互依賴。這里其實有兩個層面的意思。一是文件與文件之間,一個頭文件的變化,盡量不要引起其他文件的重新編譯;二是工程與工程之間,對一個工程的修改,盡量不要引起太多其他工程的編譯。這就要求頭文件,或者工程的內容一定要單一,不要什麼東西都往裡面塞,從而引起不必要的依賴。這也可以說是內聚性吧。
以頭文件為例,不要把兩個不相關的類,或者沒什麼聯系的宏定義放到一個頭文件里。內容要盡量單一,從而不會使包含他們的文件包含了不需要的內容。記得我們曾經做過這么一個事,把代碼中最"hot"的那些頭文件找出來,然後分成多個獨立的小文件,效果相當可觀。
其實我們去年做過的refactoring,把眾多DLL分離成UI與Core兩個部分,也是有著相同的效果的 - 提高開發效率。
4、刪除冗餘的頭文件
一些代碼經過上十年的開發與維護,經手的人無數,很有可能出現包含了沒用的頭文件,或重復包含的現象,去掉這些冗餘的include是相當必要的。當然,這主要是針對cpp的,因為對於一個頭文件,其中的某個include是否冗餘很難界定,得看是否在最終的編譯單元中用到了,而這樣又可能出現在一個編譯單元用到了,而在另外一個編譯單元中沒用到的情況。
之前曾寫過一個Perl腳本用來自動去除這些冗餘的頭文件,在某個工程中竟然去掉多達了5000多個的include。
5、特別注意inline和template
這是C++中兩種比較"先進"的機制,但是它們卻又強制我們在頭文件中包含實現,這對增加頭文件的內容,從而減慢編譯速度有著很大的貢獻。使用之前,權衡一下。
二、綜合技巧
1、預編譯頭文件(PCH)
把一些常用但不常改動的頭文件放在預編譯頭文件中。這樣,至少在單個工程中你不需要在每個編譯單元里一遍又一遍的load與解析同一個頭文件了。
2、Unity Build
Unity Build做法很簡單,把所有的cpp包含到一個cpp中(all.cpp) ,然後只編譯all.cpp。這樣我們就只有一個編譯單元,這意味著不需要重復load與解析同一個頭文件了,同時因為只產生一個obj文件,在鏈接的時候也不需要那麼密集的磁碟操作了,估計能有10x的提高,看看這個視頻感受一下其做法與速度吧。
3、ccache
compiler cache, 通過cache上一次編譯的結果,使rebuild在保持結果相同的情況下,極大的提高速度。我們知道如果是build,系統會對比源代碼與目標代碼的時間來決定是否要重新編譯某個文件,這個方法其實並不完全可靠(比如從svn上拿了上個版本的代碼),而ccache判斷的原則則是文件的內容,相對來講要可靠的多。
很可惜的是,Visual Studio現在還不支持這個功能 - 其實完全可以加一個新的命令,比如cache build,介於build與rebuild之間,這樣,rebuild就可以基本不用了。
4、不要有太多的Additional Include Directories
編譯器定位你include的頭文件,是根據你提供的include directories進行搜索的。可以想像,如果你提供了100個包含目錄,而某個頭文件是在第100個目錄下,定位它的過程是非常痛苦的。組織好你的包含目錄,並盡量保持簡潔。
三、編譯資源
要提高速度,要麼減少任務,要麼加派人手,前面兩個方面講得都是減少任務,而事實上,在提高編譯速度這塊,加派人手還是有著非常重要的作用的。
1、並行編譯
買個4核的,或者8核的cpu,每次一build,就是8個文件並行著編,那速度,看著都爽。 要是你們老闆不同意,讓他讀讀這篇文章:Hardware is Cheap, Programmers are Expensive
2、更好的磁碟
我們知道,編譯速度慢很大一部分原因是磁碟操作,那麼除了盡可能的減少磁碟操作,我們還可以做的就是加快磁碟速度。比如上面8個核一塊工作的時候,磁碟極有可能成為最大的瓶頸。買個15000轉的磁碟,或者SSD,或者RAID0的,總之,越快越好。
3、分布式編譯
一台機子的性能始終是有限的,利用網路中空閑的cpu資源,以及專門用來編譯的build server來幫助你編譯才能從根本上解決我們編譯速度的問題,想想原來要build 1個多小時工程的在2分鍾內就能搞定,你就知道你一定不能沒有它 - Incredibuild。
4、並行,其實還可以這么做。
這是一個比較極端的情況,如果你用了Incredibuild,對最終的編譯速度還是不滿意,怎麼辦?其實只要跳出思維的框架,編譯速度還是可以有質的飛躍的 - 前提是你有足夠多的機器:
假設你有solution A和solution B,B依賴於A,所以必須在A之後Build B。其中A,B Build各需要1個小時,那麼總共要2個小時。可是B一定要在A之後build嗎?跳出這個思維框架,你就有了下述方案:
◦同時開始build A和B 。
◦A的build成功,這里雖然B的build失敗了,但都只是失敗在最後的link上。
◦重新link B中的project。
⑷ delphi編譯器效率高到底是指什麼
所謂delphi編譯器效率高,一般指的是以下三方面:
1、編譯連接時間短,這一點是其他任何編譯器都無法相比的(一般來說,VC, VB編譯過程所用的時間是Delphi的幾倍),原因很簡單:Pascal語法限制嚴格,用戶必須規范地編碼,省去了編譯器的很多麻煩。
2、編譯出的程序執行速度快,產生的代碼長度短。這一點比VB強,但和VC基本一樣,誰也沒有優勢。不過很多人有誤解,以為Delphi類庫龐大復雜,加一個控制項就要把整個一個源文件全部加進來,代碼長度太大,效率太差。其實真實情況是,擁有眾多VCL控制項類庫,是Delphi的一個獨特之處,VC的MFC庫無法與之相比——MFC有的底層簡單封裝的類,VCL庫都有,但VCL有的上層組件,MFC卻根本沒有。使用VCL上層應用控制項後,代碼長度的確比VC大,不過VC卻沒有這方面的選擇,而VC所用的從底層一磚一瓦地編碼的方式,Delphi完全支持,而且絕對沒任何劣勢,代碼長度也不長(VC的語法復雜,按C程序員一般習慣做的話,代碼長的反而會是VC)。產生誤解的原因,是多數Delphi程序員是應用級的,而VC程序員是底層些的,應用程序員大多不太懂得底層代碼的編寫,只會搬控制項、響應事件,以為底層的東西Delphi做不來。
3、對應用級的程序開發周期短——這也就是Borland一貫吹捧的「快速開發工具」的含義。正因為VCL的存在(封裝了很多界面組件以及通訊、資料庫、internet應用等很多後台功能),對高層應用不再需要一磚一瓦地受累,使開發周期縮短了很多倍。
單純從技術角度說,編譯器效率應該指編譯出的代碼是否短小/運行速度是否快,以及是否能用較少的源代碼高效地實現復雜功能。前一方面Delphi並不比VC差,而比VB強,但並非一騎絕塵;後一方面則的確有一騎絕塵之象。
Delphi的致命缺點,其實不是技術——技術它是領先的,毫無疑問,問題是市場策略和公司實力(Borland只是家小公司),微軟「攜操作系統以令諸侯」,誤導了眾多軟體開發公司,讓它們以為微軟的才正宗和好用,造成了事實上的VB,VC用戶群遠比Borland的龐大,源代碼數量也一樣是C/C++遠遠占優,而Borland的C++ Builder卻開發得太晚難以形成市場優勢。
概括來說,如果你要開發上層應用為主的程序,特別是資料庫方面的程序,那麼Delphi能讓你省不少時間;而若開發底層些的軟體,為能有更多相關代碼可以參考利用,為能容易地招聘到更合適的程序員,以及為了代碼維護方便,都適合用C/C++去做,當然,C++ Builder從技術上說是個不錯的選擇,只是用戶群還太小。
⑸ java 代碼的運行效率是由Java虛擬機決定,還是由我們的PC速度決定
運行效率分兩個部分,一個是編譯的效率,一個是執行的效率。
編譯的效率是由jvm和pc兩部分影響的,編譯後的class文件的執行速度就完全由pc決定了,這個和你的代碼中是否有循環沒有直接關系,執行所耗費的時間是按照計算機計算一個二進制基礎運算的基礎來衡量的。這裡面還有class文件解釋成機器碼的時間,這個就是按語句的多少來算了,因為java是逐行逐句解釋的。所以我們說class文件的運行時間也包含了class文件解釋成機器碼的時間。
不過java運行效率再快,也沒有c代碼快,這個不是說c代碼精煉就運行快的原因。
java代碼通過jvm編譯成class文件,這時候還不能說是編譯成機器碼了,class碼呢還是一種中間碼,還需要被解釋成機器碼,這也是為什麼java是跨平台的語言的原因。而c代碼,只需要直接一次性編譯成機器碼就可以了。這也是為什麼在某種平台下寫的c代碼不能再跨平台的原因。
希望我已經解釋清楚了。
項目越來越大,每次需要重新編譯整個項目都是一件很浪費時間的事情。Research了一下,找到以下可以幫助提高速度的方法,總結一下。
1. 使用tmpfs來代替部分IO讀寫
2.ccache,可以將ccache的緩存文件設置在tmpfs上,但是這樣的話,每次開機後,ccache的緩存文件會丟失
3.distcc,多機器編譯
4.將屏幕輸出列印到內存文件或者/dev/null中,避免終端設備(慢速設備)拖慢速度。
tmpfs
有人說在Windows下用了RAMDisk把一個項目編譯時間從4.5小時減少到了5分鍾,也許這個數字是有點誇張了,不過粗想想,把文件放到內存上做編譯應該是比在磁碟上快多了吧,尤其如果編譯器需要生成很多臨時文件的話。
這個做法的實現成本最低,在Linux中,直接mount一個tmpfs就可以了。而且對所編譯的工程沒有任何要求,也不用改動編譯環境。
mount -t tmpfs tmpfs ~/build -o size=1G
用2.6.32.2的Linux Kernel來測試一下編譯速度:
用物理磁碟:40分16秒
用tmpfs:39分56秒
呃……沒什麼變化。看來編譯慢很大程度上瓶頸並不在IO上面。但對於一個實際項目來說,編譯過程中可能還會有打包等IO密集的操作,所以只要可能,用tmpfs是有益無害的。當然對於大項目來說,你需要有足夠的內存才能負擔得起這個tmpfs的開銷。
make -j
既然IO不是瓶頸,那CPU就應該是一個影響編譯速度的重要因素了。
用make -j帶一個參數,可以把項目在進行並行編譯,比如在一台雙核的機器上,完全可以用make -j4,讓make最多允許4個編譯命令同時執行,這樣可以更有效的利用CPU資源。
還是用Kernel來測試:
用make: 40分16秒
用make -j4:23分16秒
用make -j8:22分59秒
由此看來,在多核CPU上,適當的進行並行編譯還是可以明顯提高編譯速度的。但並行的任務不宜太多,一般是以CPU的核心數目的兩倍為宜。
不過這個方案不是完全沒有cost的,如果項目的Makefile不規范,沒有正確的設置好依賴關系,並行編譯的結果就是編譯不能正常進行。如果依賴關系設置過於保守,則可能本身編譯的可並行度就下降了,也不能取得最佳的效果。
ccache
ccache工作原理:
ccache也是一個編譯器驅動器。第一趟編譯時ccache緩存了GCC的「-E」輸出、編譯選項以及.o文件到$HOME/.ccache。第二次編譯時盡量利用緩存,必要時更新緩存。所以即使"make clean; make"也能從中獲得好處。ccache是經過仔細編寫的,確保了與直接使用GCC獲得完全相同的輸出。
ccache用於把編譯的中間結果進行緩存,以便在再次編譯的時候可以節省時間。這對於玩Kernel來說實在是再好不過了,因為經常需要修改一些Kernel的代碼,然後再重新編譯,而這兩次編譯大部分東西可能都沒有發生變化。對於平時開發項目來說,也是一樣。為什麼不是直接用make所支持的增量編譯呢?還是因為現實中,因為Makefile的不規范,很可能這種「聰明」的方案根本不能正常工作,只有每次make clean再make才行。
安裝完ccache後,可以在/usr/local/bin下建立gcc,g++,c++,cc的symbolic link,鏈到/usr/bin/ccache上。總之確認系統在調用gcc等命令時會調用到ccache就可以了(通常情況下/usr/local /bin會在PATH中排在/usr/bin前面)。
安裝的另外一種方法:
vi ~/.bash_profile
把/usr/lib/ccache/bin路徑加到PATH下
PATH=/usr/lib/ccache/bin:$PATH:$HOME/bin
這樣每次啟動g++的時候都會啟動/usr/lib/ccache/bin/g++,而不會啟動/usr/bin/g++
效果跟使用命令行ccache g++效果一樣
這樣每次用戶登錄時,使用g++編譯器時會自動啟動ccache
繼續測試:
用ccache的第一次編譯(make -j4):23分38秒
用ccache的第二次編譯(make -j4):8分48秒
用ccache的第三次編譯(修改若干配置,make -j4):23分48秒
看來修改配置(我改了CPU類型...)對ccache的影響是很大的,因為基本頭文件發生變化後,就導致所有緩存數據都無效了,必須重頭來做。但如果只是修改一些.c文件的代碼,ccache的效果還是相當明顯的。而且使用ccache對項目沒有特別的依賴,布署成本很低,這在日常工作中很實用。
可以用ccache -s來查看cache的使用和命中情況:
cache directory /home/lifanxi/.ccachecache hit 7165cache miss 14283called for link 71not a C/C++ file 120no input file 3045files in cache 28566cache size 81.7 Mbytesmax cache size 976.6 Mbytes
可以看到,顯然只有第二編次譯時cache命中了,cache miss是第一次和第三次編譯帶來的。兩次cache佔用了81.7M的磁碟,還是完全可以接受的。
distcc
一台機器的能力有限,可以聯合多台電腦一起來編譯。這在公司的日常開發中也是可行的,因為可能每個開發人員都有自己的開發編譯環境,它們的編譯器版本一般是一致的,公司的網路也通常具有較好的性能。這時就是distcc大顯身手的時候了。
使用distcc,並不像想像中那樣要求每台電腦都具有完全一致的環境,它只要求源代碼可以用make -j並行編譯,並且參與分布式編譯的電腦系統中具有相同的編譯器。因為它的原理只是把預處理好的源文件分發到多台計算機上,預處理、編譯後的目標文件的鏈接和其它除編譯以外的工作仍然是在發起編譯的主控電腦上完成,所以只要求發起編譯的那台機器具備一套完整的編譯環境就可以了。
distcc安裝後,可以啟動一下它的服務:
/usr/bin/distccd --daemon --allow 10.64.0.0/16
默認的3632埠允許來自同一個網路的distcc連接。
然後設置一下DISTCC_HOSTS環境變數,設置可以參與編譯的機器列表。通常localhost也參與編譯,但如果可以參與編譯的機器很多,則可以把localhost從這個列表中去掉,這樣本機就完全只是進行預處理、分發和鏈接了,編譯都在別的機器上完成。因為機器很多時,localhost的處理負擔很重,所以它就不再「兼職」編譯了。
export DISTCC_HOSTS="localhost 10.64.25.1 10.64.25.2 10.64.25.3"
然後與ccache類似把g++,gcc等常用的命令鏈接到/usr/bin/distcc上就可以了。
在make的時候,也必須用-j參數,一般是參數可以用所有參用編譯的計算機CPU內核總數的兩倍做為並行的任務數。
同樣測試一下:
一台雙核計算機,make -j4:23分16秒
兩台雙核計算機,make -j4:16分40秒
兩台雙核計算機,make -j8:15分49秒
跟最開始用一台雙核時的23分鍾相比,還是快了不少的。如果有更多的計算機加入,也可以得到更好的效果。
在編譯過程中可以用distccmon-text來查看編譯任務的分配情況。distcc也可以與ccache同時使用,通過設置一個環境變數就可以做到,非常方便。
總結一下:
tmpfs: 解決IO瓶頸,充分利用本機內存資源
make -j: 充分利用本機計算資源
distcc: 利用多台計算機資源
ccache: 減少重復編譯相同代碼的時間
這些工具的好處都在於布署的成本相對較低,綜合利用這些工具,就可以輕輕鬆鬆的節省相當可觀的時間。上面介紹的都是這些工具最基本的用法,更多的用法可以參考它們各自的man page。
5.還有提速方法是把屏幕輸出重定向到內存文件或/dev/null,因對終端設備(慢速設備)的阻塞寫操作也會拖慢速度。推薦內存文件,這樣發生錯誤時,能夠查看。