為什么大多數(shù)編程語言性能對(duì)比都有問題?
01?等效的實(shí)現(xiàn)?
為了公平地比較兩種語言的實(shí)現(xiàn),編寫出來的程序的質(zhì)量應(yīng)該達(dá)到同等水平。也就是說,必須由某位對(duì)兩種編程語言以及領(lǐng)域知識(shí)的掌握程度大致相同的人來編寫程序。這本身就很難。如果由不同的人來編寫實(shí)現(xiàn),那么他們可能會(huì)選擇不同的算法來解決問題,這樣的性能比較就不再是編程語言本身的問題,而是每位程序員選擇的編程方法的問題。即使兩個(gè)實(shí)現(xiàn)都是由同一個(gè)人使用相同的算法編寫的,仍然存在其他問題。通常,每個(gè)人都有自己擅長的語言。因此,他們會(huì)選擇自己喜歡的語言提供更快的實(shí)現(xiàn)。這就會(huì)引發(fā)偏差,因?yàn)檫@樣的性能比較衡量的不是編程語言本身,而更多的是程序員。這類的測(cè)試適合尋找易用性與生產(chǎn)力的差異,但對(duì)比較性能而言則不合適。因此,你可能需要評(píng)估許多專業(yè)程序員已經(jīng)編寫好的程序。這是一個(gè)很好的方法,但有時(shí)即使是經(jīng)驗(yàn)豐富的研究也會(huì)出錯(cuò)。有一篇論文試圖通過這種方法比較不同的編程語言的性能和效率。他們的測(cè)試結(jié)果表明,某個(gè)程序用C實(shí)現(xiàn)比C 實(shí)現(xiàn)快30%。這個(gè)測(cè)試結(jié)果影響了整個(gè)論文的基調(diào)。按照這個(gè)論斷,假設(shè)將所有 C 源代碼的文件擴(kuò)展名 .c 改為.cpp并重新編譯,應(yīng)該能得到大致相同的結(jié)果(可能會(huì)有幾個(gè)百分點(diǎn)的誤差)。所以我們只能得出以下結(jié)論(按照可能性從高到低排列):
- C 版本的代碼比較差;
- 測(cè)試方法有明顯的瑕疵;
- 與C相比,該編譯器對(duì)C 的性能有重大的負(fù)面影響。
02?測(cè)量的難度
?還有一個(gè)很大的問題是,如何測(cè)量某個(gè)程序的性能。一種常見的方法是連續(xù)運(yùn)行多次測(cè)試,然后執(zhí)行如下操作:- 處理異常值:去掉兩個(gè)極值(即最慢和最快的測(cè)量值);
- 計(jì)算剩余數(shù)據(jù)點(diǎn)的平均值和/或中位數(shù);
- 比較不同程序之間的結(jié)果,速度最快的程序獲勝。
03?統(tǒng)計(jì)的難度更大
?暫時(shí)撇開這一點(diǎn)不談,我們假設(shè)我們獲得了兩個(gè)程序的性能測(cè)試結(jié)果,且這個(gè)結(jié)果看似確實(shí)“很高斯”。數(shù)值分析表明,1號(hào)語言的運(yùn)行花費(fèi)了10秒,而2號(hào)語言花費(fèi)了9秒。二者的差異為10%,因此我們就可以得出結(jié)論:2號(hào)語言的速度更快。這個(gè)結(jié)果正確嗎?很遺憾,不正確。假設(shè)實(shí)際測(cè)量數(shù)據(jù)如下:?右邊的那個(gè)更快,對(duì)不對(duì)?也許?大概?可能?為了正確回答這個(gè)問題,我們需要回顧一下大學(xué)學(xué)習(xí)的統(tǒng)計(jì)知識(shí)。首先,提出零假設(shè),即假設(shè)兩個(gè)程序沒有性能差異。接著,計(jì)算這兩次測(cè)量結(jié)果來自同一個(gè)概率分布的概率。如果概率非常?。ㄍǔ?%),則可以推翻零假設(shè),從而證明其中一個(gè)程序比另一個(gè)快。這種方法叫做學(xué)生t檢驗(yàn),常用于大量數(shù)據(jù)的統(tǒng)計(jì)。請(qǐng)注意,測(cè)試的某些實(shí)現(xiàn)會(huì)假設(shè)數(shù)據(jù)符合高斯分布,如果你的數(shù)據(jù)呈現(xiàn)其他形狀,則結(jié)果可能并不可靠。這種方式適用于一個(gè)程序,但嚴(yán)格的測(cè)試需要包含多個(gè)程序。這些評(píng)估也有一些統(tǒng)計(jì)方法,但會(huì)非常復(fù)雜。具體的做法留給讀者自行查閱。
04?所有計(jì)算機(jī)的對(duì)齊都是雙刃劍
?雖然統(tǒng)計(jì)非常難,但幸運(yùn)的是計(jì)算機(jī)很簡(jiǎn)單,因?yàn)樗鼈兙哂写_定性、可靠,而且合乎邏輯。例如,如果在一個(gè)程序中添加一條NOP指令,則結(jié)果可能只是多了一個(gè)指令周期,對(duì)性能的影響小到無法測(cè)量。但是,如果你非要測(cè)量,那么結(jié)果可能會(huì)讓你陷入不解和困惑。這個(gè)小小的改動(dòng)有時(shí)會(huì)讓程序的運(yùn)行時(shí)間增加10%(甚至更長),但也有可能縮短10%。你沒看錯(cuò),這類看似無意義的工作可以加快程序的運(yùn)行速度。如果是第一次遇到這樣的問題,你可能壓根不會(huì)相信。?那么,問題在于,是否有可能讓CPU加倍努力,讓程序更快地運(yùn)行呢?答案為否。實(shí)際的指令根本無關(guān)緊要。重點(diǎn)在于代碼的對(duì)齊。代碼在內(nèi)存中的不同位置會(huì)影響其性能特征。如果一段經(jīng)常被執(zhí)行的循環(huán)跨越了緩存邊界,它就會(huì)變慢。將其移動(dòng)到不跨越邊界的地方就能加快其速度。NOP指令并不一定要放在循環(huán)內(nèi),只要它能將整個(gè)代碼塊向上或向下移動(dòng),就可能導(dǎo)致這種差異。假設(shè)你以非常嚴(yán)謹(jǐn)?shù)慕y(tǒng)計(jì)方式測(cè)量了兩個(gè)程序。如果二者之間的性能差異低于10%,則我們就無法斷言哪個(gè)程序更快,除非你使用的測(cè)量方式能夠消除對(duì)齊效應(yīng)。05?這是關(guān)于機(jī)器的性能測(cè)量,而不是語言
?隨著程序的運(yùn)行速度越來越快,優(yōu)化經(jīng)歷了一個(gè)有趣的階段轉(zhuǎn)變。一旦性能達(dá)到一定水平,系統(tǒng)就不再關(guān)心編譯器和CPU如何才能加快程序的運(yùn)行速度。相反,變成了程序員如何盡可能有效地利用CPU,例如將數(shù)據(jù)排列成方便處理器處理的布局等。這意味著用基于硬件的原語替換基于語言的原語。某些圈子采用的優(yōu)化方式非常奇怪,程序員甚至知道他們的循環(huán)應(yīng)該被優(yōu)化成哪些SIMD指令,然后他們會(huì)不停地修改代碼,直到實(shí)現(xiàn)這種優(yōu)化。其實(shí),這種優(yōu)化已經(jīng)與編程語言本身的功能沒有絲毫關(guān)系了。這就是為什么C和Fortran之類的語言仍在許多性能基準(zhǔn)測(cè)試中名列前茅的主要原因,但這些技巧并不限于這些語言。幾年前,我開發(fā)了一款規(guī)模非常大的Java應(yīng)用程序,該應(yīng)用程序經(jīng)過了非常徹底的優(yōu)化。其內(nèi)部由整數(shù)數(shù)組組成。最常執(zhí)行的路徑中沒有類,甚至沒有Integer對(duì)象,基本上就形同于在Java語言內(nèi)部重塑了C語言。其實(shí),幾乎任何編程語言都可以有類似的實(shí)現(xiàn)。它們之間的性能差異主要取決于每個(gè)編譯器的優(yōu)化器。即便使用相同的編程語言,也會(huì)產(chǎn)生截然不同的性能結(jié)果,更不用說不同的編程語言了。因此,聲稱某一種編程語言在性能上有明顯的優(yōu)勢(shì)都是不合理的,因?yàn)檎f到底都是內(nèi)聯(lián)匯編程序。原文鏈接:
https://nibblestew.blogspot.com/2021/02/why-most-programming-language.html?m=1END
來源:CSDN版權(quán)歸原作者所有,如有侵權(quán),請(qǐng)聯(lián)系刪除。
▍