奇了個怪
.NET作為開發平臺來說,不可否認是優雅的、高效的。可是有些人就是看不到它極高的開發效率,極短的市場推出時間,極強的擴充套件能力,非得在效能上較勁,把一幫小萌新忽悠得一說起 .NET就覺著是“慢”、“卡”的代名詞。
這些人總是存在一個思維誤區,認為程式效能是和語言掛鉤的。您沒事兒吧?真要這樣,《資料結構》、《演演算法》這些課早他媽該撤了好吧。汽車和飛機速度確實不一樣,但就算給您一架私人飛機,您能給表演表演每天開飛機去買菜?任何語言的效能瓶頸,大半還是出在使用這語言的人身上。新手司機開著十輛布加迪也不可能拼過馳騁秋名山的五菱宏光老司機。咱們不抬槓,今天就只說效能,不說開發效率、上市速度。非要跟我抬槓,算上這些,可能我的“低效能”產品已經出街了,你憋半天憋不出屁的“高效能”產品快撲街了,優越個?8呢。
.NET的開發語言一般用C#,後邊我就不區分 .NET和C# 了。F# 其實也差不多,反正最後都編譯成intermediate language,可以認為是等價的(函式式程式設計更多的是一種思想,這個話題我以後會寫)。實話實說,C# 這門程式語言,一開始就處於一個挺尷尬的位置。效能上,有C/C++ 在前邊攔著;應用上,有Java、Python在後邊堵截,不上不下。.NET玩家心裡總憋著股邪火,只好左右互搏,自娛自樂了。
語言的比較
這個問題的根源,很大一部分在於很多程式員只會一種語言,甚至連這唯一的語言也不夠精通,所以才會要麼看不起別的語言,要麼埋怨自己這語言效能太弱。想要一招鮮吃遍天,夢裡可以,醒來最好還是把這茬給忘了。而那些對 .NET一知半解就開始嘲諷的“別的語言”玩家,就更別指望他們能理解到其中的精髓了。
把自己限制於一種語言的程式員會經常錯過其他地方提供的重要機會。這樣的程式員絕對不會被他們的老闆或客戶看成是專業領域中的專家。
C# 雖然定位尷尬,但是它本身是高度最佳化的,要比效能,無非就C/C++ 或者彙編才配跟它比。Java、Python這些,大家都是IL解釋的,本是同根生,相煎急鎚子,都不一定能比過C#。C系玩家就算了,特性使然確實比不過,但是事實上最佳化之後效能也大差不差(我馬上就能證明這一點)。最奇怪的就是好多J、P玩家居然好意思笑話C# 效能辣雞,完全沒意識到自己那慘樣兒。就好像宋小寶去夠姚明手裡的球,結果潘長江在邊兒上笑得挺歡,笑您 ? 呢?和機器碼比起來,任何使用中間語言虛擬機器/runtime的語言都有損失,這話沒人能反駁吧?Benchmark,一般都是用最耗資源的操作——比如影象處理——來比較。這無非就是測試磁碟、記憶體的IO效能唄。作業系統最終的效能在那卡著,assembly可以達到95%,C系8、90%,C# 可能虧點兒,6、70%的樣子。然而,這都不是重點,重點在於,你有沒有完全利用到語言的全部特性,以及那些你認為低效率的演演算法,非要用它們真的大丈夫?40米大刀拿來削蘋果,可能它的效能真的很低吧。
我過去的試驗
2012年的時候我就測試過用C# GDI+讀寫bitmap,一開始用的常規演演算法,很慢。但是經過最佳化後,效能提升了363倍,我也沒用別的任何類庫,還是 .NET 2.0原生。您說怎麼判斷C# 的效能到底是低還是高?
當時一幫哥們兒看了我的試驗都手癢秀了一遍最佳化:
滑鼠移到作者名字上可以檢視作者資訊
編號 | 作者 | 耗時(毫秒) | 實現方法 | 平臺 |
---|---|---|---|---|
a. | laviewpbt | 25 | 彙編 + PowerBasic | i3 380M/3GB/Win7 32-bit |
b. | 蘭徵鵬 | 12~19 | VC++.NET呼叫SSE指令 | i7 860/12GB/Win7 64-bit |
c. | 胡飛 | 33 | 重寫C# 影象庫、unsafe 指標 |
優於 a |
d. | Conmajia | 46 | 原生GDI+、unsafe 指標 |
同a |
上面這張表,可以看到,幾種語言的效能是接近的,相差最大20毫秒(C# vs 彙編)。除了b項C++ 加了buff(當時i7是頂級CPU),換到同平臺,基本差不多的。當技巧和演演算法都最佳化到極致之後,其實C#、VB、C++ 的效能非常接近了,輕微的差異在大部分場景下幾乎是可以忽略的。這一點,我以前這個試驗就是很好的解釋。計算機技術發展到今天,語言的執行效率差異早就可以忽略不計了,方法論和演演算法的才是核心。
重新再試驗
有人說,跟程式員交流,不要說那麼多話,要麼秀程式碼,要麼秀妹子。那麼我接下來就請出網際網路的first lady——瑞典模特Lena Soderberg(展示的樣本經過了處理)。Lena的介紹可以看昨天的新聞:《花花公子》的封面女郎,計算機影象界的女神。
Lena是瑞典拼法,Lenna是英文拼法。
測試圖我用Lena原圖,超高畫質3831×8192@24bpp,檔案大小94.2MB。影象樣本可以在 lenna.org 獲得。
拿DIP裡最最簡單的反色舉例,同樣用C#,一個萌新和一個大神分別實現,那最後的效率可差老了去了。不信咱來試試。
萌新的實現:單執行緒managed
這個例子雖然有點兒欺負人,但它確實是實際存在的現象。新手玩家不管是熟練度還是連招都跟老油條沒得比。
private void invert(Bitmap bmp) {
Color sc = new Color(); // 逐畫素處理
for (int i = 0; i < bmp.Width; i++) { for (int j = 0; j < bmp.Height; j++) {
sc = bmp.GetPixel(i, j);
bmp.SetPixel(i, j, Color.FromArgb(0xff - sc.R, 0xff - sc.G, 0xff - sc.B));
}
}
}
這種做法理論上是沒錯的,也能實現效果,就是太慢了。於是萌新可能就開始罵街:C# 真辣雞,.NET真辣雞。可是大哥,您這演演算法就他媽的辣雞啊!這種單執行緒的managed語法,想快它也快不起來啊。
大神的實現:平行計算unsafe
大神之所以能叫大神,因為他們可以利用語言以及計算機的全部實力。思路上,他們能夠選用最佳的合適演演算法;技巧上,他們可以挖掘電腦的所有潛力。同樣的語言,不同的效能,我再次提出那個問題:你說瓶頸在語言還是在人?
萌新 vs 大神
看看結果吧!42466ms對上101ms,420倍的差距。誰跟我說 .NET效能差來著?請大點兒聲,謝謝!?
完畢
其實就上面的例子來說,還能把效能再往上提,但這都是次要的。我想表達的意思已經表達完了:.NET的效能並不低,如果你覺得低,那可能是因為你的能力低。
原文地址:https://www.cnblogs.com/conmajia/p/low-performance-csharp-all-your-fault.html
.NET社群新聞,深度好文,歡迎訪問公眾號文章彙總 http://www.csharpkit.com