【CSDN編譯整理】近日,beza1e1上發表了一篇博客《Faster than C》,在Hacker News和Reddit Programming上引發了開發者們的激烈討論。現將此文編譯,我們一起來探討下。
單從編程語言特性來判斷,雖然Fortran語言也以快而著稱,但開發者們還是將C語言稱之為領導者。開發者創建新一門語言通常以C語言為參照對象,將語言編譯時間與C語言進行對比,會因比C語言慢多少而引以自傲。然而,很少有語言能夠擊敗C。
那么,什么樣的語言才能比C更快呢?
更好的別名機制(Better Aliasing Information)
別名實際上是指兩個引用指向同一個內存位置。例如,典型的內存復制(not memcpy from stdlib.h!)
- void*?memcopy(void*?dst,?const?void*?src,?size_t?count)?{ ?
- ???while?(count--)?*dst++?=?*src++; ?
- ???return?dst; ?
- }?
根據目標架構,編譯器利用代碼對此進行大量的優化。比如,X86利用SSE指定MOVDQU,它可以復制16字節,而非4字節(sizeof(void*))。然而,因為Aliasing(別名),dst中以src+1為例,在這種情況下,結果在dst出現的第一句一定是*src,由于C語義的原因,編譯器不允許使用MOVDQU。
在C99中新增了限制性關鍵字,我們在這里使用的編碼src和dst與其他地方引用的不同。在某些情況下這種機制比較受用,能夠起到幫助,但在我們的例子中卻不受用。
Fortran語義稱函數參數從未有過別名(alias ),Fortran中單獨有數組類型,而在C中,數組實質上是指針。這就是為什么Fortran經常比C更快的原因以及為什么依然要在Fortran中編譯數值庫的原因,當然它還涉及到指針算法的成本問題。
因此,想要創建一門比C更快的語言應該提供更容易被編譯器處理的別名機制。
在編譯階段完成運算(Push Computation to Compile-Time)
在編譯時應當減少運行時間,當然,在C編譯器像1+2這樣的案例,加法運算在編譯階段就完成了。編程語言利用完美的元編程語言能夠使程序員可以做一些特定優化的應用。一個簡單的實例,比如fib(20)可以寫成6765。一個真實的例子,Eigen C++ library for linear algebra通過使用C++模板來避免復制和一些計算指令 。Lisp是宏觀系統技術之父。比如,一個學生使用Scheme的編碼奇聞。基本上,程序員可以在編譯過程中修改抽象的語法樹,用這樣的元編程特性來權衡是很復雜的。程序員往往會低估了如何編譯正確宏的困難性如同他們會低估如何編譯正確的并發程序一樣。
一門語言的設計者應該好好思考下元編程。在編譯的時候多思考要像C++ 模板那樣能夠提供多種益處的性能。
運行優化(Runtime Optimization)
在運行時,有動態信息顯示不適用于靜態編譯器,C語言可以復制任何一個特定的示例,一般情況下,它是不可行的。該技巧只解決了問題的一小部分。
運行時優化whole-world變得相當的容易。盡管這可能是靜態的,C語義(編譯單元)和強制性的預處理器使其編譯起來更難,盡管Python通過inlining across file borders(PyPy)擊敗了C。
當然也有使用JIT,但在嵌入式系統語言是不適宜的。雖然Java,C#或者是其他語言擊敗了C,但它們不會威脅到C的用戶群。
結束語:
想要創建一門比C要快的新的語言,更好的別名機制是我唯一確定能提高語言速度的方法,因為在C中無法實現Fortran的速度,另外就是思考如何用更簡單的方法編寫出更快的程序。