簡體   English   中英

為什么Go這么慢(與Java相比)?

[英]Why is Go so slow (compared to Java)?

正如我們從2010年的計算機語言基准游戲中看到那樣:

  • Go平均比C慢10倍
  • Go比Java慢3倍!

考慮到Go編譯器生成用於執行的本機代碼,這怎么可能呢?
Go的不成熟的編譯器? 或者Go語言存在一些內在問題?

編輯:
大多數答案否認Go語言的內在緩慢,聲稱問題存在於不成熟的編譯器中。
因此,我已經做了一些自己的測試來計算Fibonacci數 :迭代算法在Go(freebsd,6g)中以與C中same速度運行(使用O3選項)。 沉悶的遞歸運行在Go中運行比在C中慢2 times (使用-O3選項;使用-O0 - 相同)。 但我沒有看到基准游戲中的10倍跌幅。

6g和8g編譯器沒有特別優化,因此它們生成的代碼不是特別快。

它們被設計為自己快速運行並生成可以正常運行的代碼(有一些優化)。 gccgo使用GCC現有的優化通道,可能會提供與C的更有意義的比較,但gccgo尚未完成功能。

基准數字幾乎完全與實施質量有關。 它們與語言本身並沒有太大關系,除非實現花費運行時支持基准測試並不真正需要的語言功能。 在大多數編譯語言中,一個足夠聰明的編譯器理論上可以刪除不需要的東西,但是有一個點你需要操作演示,因為很少有真正的語言用戶會編寫沒有使用該功能的程序。 在不完全刪除它們的情況下將事物移開(例如,在JIT編譯的Java中預測虛擬調用目標)開始變得棘手。

FWIW,當我看一下它時,我自己非常瑣碎的測試(基本上是一個整數加法的循環),gccgo為gcc -O0gcc -O2之間的范圍的快速結束生成了代碼C. Go本質上並不慢,但編譯器並沒有做任何事情。 對於一種10分鍾的語言來說,這簡直令人驚訝。

Go FAQ的下一個版本中,應該出現類似於以下內容的內容。

性能

為什么Go在基准X上表現不佳?

Go的設計目標之一是為可比較的程序接近C的性能,但在某些基准測試中,它的表現相當差,包括測試/工作台中的幾個。 最慢的依賴於庫,Go中沒有可用性能相當的庫。 例如,pidigits依賴於多精度數學包,而C版本與Go不同,使用GMP(用優化的匯編程序編寫)。 依賴於正則表達式的基准(例如regex-dna)本質上是將Go的stopgap regexp包與成熟的,高度優化的正則表達式庫(如PCRE)進行比較。

通過廣泛的調整贏得基准游戲,大多數基准測試的Go版本需要引起注意。 如果你測量可比較的C和Go程序(反向補充是一個例子),你會發現兩種語言的原始性能比這個套件所表明的要接近得多。

不過,還有改進的余地。 編譯器很好但可能更好,許多庫需要主要的性能工作,垃圾收集器還不夠快(即使它是,注意不要產生不必要的垃圾會產生巨大的影響)。

以下是最近郵件列表主題中關於計算機基准游戲的更多詳細信息。

gccgo的垃圾收集和性能(1)

gccgo的垃圾收集和性能(2)

值得注意的是,計算機基准游戲只是一款游戲。 具有性能測量和容量規划經驗的人員可以像現實和實際工作負載一樣仔細匹配; 他們不玩游戲。

我的回答並不像其他人那樣技術性,但我認為它仍然具有相關性。 當我決定開始學習Go時,我在計算機基准游戲中看到了相同的基准。 但老實說,我認為所有這些綜合基准測試在決定Go是否足夠快的方面毫無意義。

我最近使用Tornado + TornadIO + ZMQ在Python中編寫了一個消息服務器,對於我的第一個Go項目,我決定在Go中重寫服務器。 到目前為止,讓服務器具有與Python版本相同的功能,我的測試向我展示了Go程序中4.7倍的速度提升。 請注意,我只在Go中編寫了一個星期的代碼,而且我已經用Python編寫了超過5年的編碼。

Go只會在它們繼續工作時變得更快,我認為它實際上歸結為它在現實世界的應用程序中的表現,而不是微小的計算基准。 對我來說,Go顯然比我在Python中生成的程序更有效。 這是我對這個問題的回答。

事情變了。

我認為你問題的當前正確答案是反對這樣做的觀點。 在你的詢問時,你的判斷是合理的,但從那以后,在表現方面取得了很多進展。 現在,它仍然沒有C那么快,但是在一般意義上,它不會慢近10倍。

計算機語言基准游戲

在撰寫本文時:

source  secs    KB      gz      cpu     cpu load

reverse-complement
1.167x
Go      0.49    88,320  1278    0.84    30% 28% 98% 34%
C gcc   0.42    145,900 812     0.57    0% 26% 20% 100%

pidigits
1.21x
Go      2.10    8,084   603 2.10    0% 100% 1% 1%
C gcc   1.73    1,992   448 1.73    1% 100% 1% 0%

fasta
1.45x
Go      1.97    3,456   1344    5.76    76% 71% 74% 73%
C gcc   1.36    2,800   1993    5.26    96% 97% 100% 97%

regex-dna
1.64x
Go      3.89    369,380 1229    8.29    43% 53% 61% 82%
C gcc   2.43    339,000 2579    5.68    46% 70% 51% 72%

fannkuch-redux
1.72x
Go      15.59   952 900 62.08   100% 100% 100% 100%
C gcc   9.07    1,576   910 35.43   100% 99% 98% 94%

spectral-norm
2x
Go      3.96    2,412   548 15.73   99% 99% 100% 99%
C gcc   1.98    1,776   1139    7.87    99% 99% 100% 99%

n-body
2.27x
Go      21.73   952 1310    21.73   0% 100% 1% 2%
C gcc   9.56    1,000   1490    9.56    1% 100% 1% 1%

k-nucleotide
2.40x
Go      15.48   149,276 1582    54.68   88% 97% 90% 79%
C gcc   6.46    130,076 1500    17.06   51% 37% 89% 88%

mandelbrot
3.19x
Go      5.68    30,756  894 22.56   100% 100% 99% 99%
C gcc   1.78    29,792  911 7.03    100% 99% 99% 98%

雖然,它在二叉樹基准測試中遭受殘酷的打擊:

binary-trees
12.16x
Go      39.88   361,208 688 152.12  96% 95% 96% 96%
C gcc   3.28    156,780 906 10.12   91% 77% 59% 83%

盡管圍繞CPU周期使用效率不是很高,但Go並發模型比Java中的線程模型快得多,並且可以與C ++線程模型相媲美。

請注意,在線程環基准測試中 ,Go比Java快16倍 在相同的場景中,Go CSP幾乎與C ++相當,但使用的內存減少了4倍。

Go語言的強大功能是它的並發模型,即70年代由Tony Hoare指定的通信順序進程,CSP,易於實現並適合高度並發的需求。

我認為一個經常被忽視的事實是,JIT編譯可以是>靜態編譯,尤其是(運行時)后期綁定函數或方法。 熱點JIT在RUNTIME決定采用哪種內聯方法,甚至可以將數據布局調整為當前運行的CPU的高速緩存大小/體系結構。 通過直接訪問硬件,C / C ++通常可以彌補(並且總體上仍將表現更好)。 對於Go來說,事物可能看起來不同,因為它與C相比更高級,但目前缺少運行時優化系統/編譯器。 我的直覺告訴我,Go 可能比Java更快,因為Go不強制指針追逐那么多,並鼓勵更好的數據結構局部性+需要更少的分配。

Java比Go和C ++更快有兩個基本原因,在許多情況下可能比C更快:

1)JIT編譯器。 它可以基於運行時配置文件通過多個級別內聯虛擬函數調用,即使使用OO類也是如此。 這在靜態編譯的語言中是不可能的(盡管基於記錄的配置文件的較新的重新編譯可以提供幫助)。 這對涉及重復算法的大多數基准測試非常重要。

2)GC。 與malloc相比,基於GC的內存分配幾乎是免費的。 並且“免費”懲罰可以在整個運行時間內分攤 - 經常被跳過,因為程序在需要收集所有垃圾之前終止。

有數百(數千?)非常有才華的開發人員使GC / JVM高效。 認為你可以“比所有人更好地編碼”是一種愚蠢的行為。 這是一個人類自我問題的核心 - 人類很難接受通過有才能的人類的適當訓練,計算機將比編程它的人類表現更好。

順便說一下,如果不使用和使用OO功能,C ++可以和C一樣快,但是接下來你就開始編寫C語言了。

最重要的是,這些測試中的“速度差異”通常毫無意義。 IO成本比性能差異高出幾個數量級,因此最小化IO成本的正確設計總能獲勝 - 即使是在解釋性語言中也是如此。 很少有系統受CPU限制。

最后,人們將“計算機語言基准游戲”稱為“科學測量”。 測試是完全有缺陷的,例如,如果您查看nbody的Java測試。 當我在相同的操作系統/硬件上運行測試時,Java大約需要7.6秒,C大約需要4.7秒 - 這是合理的 - 而不是測試報告的4倍慢。 它是點擊誘餌,虛假新聞,旨在產生網站流量。

作為最終的,最后的注釋......我使用Go運行測試,它是7.9秒。 事實上,當你單擊Go時,它將它與Java進行比較,當你點擊Java時它將它與C進行比較,應該是任何嚴肅的工程師的紅旗。

對於Java,Go和C ++的真實世界比較,請參閱https://www.biorxiv.org/content/10.1101/558056v1擾碼警報,Java在原始性能方面名列前茅,Go在組合內存使用方面名列前茅和牆上的時間。

事實上,Go不僅在設計時優雅高效,而且在運行時也具有超高性能。 關鍵是使用正確的操作系統即LINUX。 Windows和Mac OS下的性能分析結果是,由於缺少一個更好的詞,比一個或兩個數量級更差。

在linux下,go運行時超快,與c / c ++完全可比。 windows和unix下的go運行時不屬於同一個聯盟

與java的比較並不那么重要,go用於系統和應用程序開發(因為java更像是僅用於應用程序開發的藍領)。 不會詳細介紹,但是當像kubernetes這樣的東西寫進去時,你會發現這不是一個企業顧問友好的玩具

我不記得谷歌提到甚至一次你提到的妥協。 go設計精良,簡單,優雅,高效,適用於設計系統和應用程序級別的程序,有指針,高效的內存分配和解除分配,避免了由於容易錯過使用實現繼承而產生的復雜性,為您提供協同例程和其他現代在時間和預算上編寫高性能應用程序的方法。 再一次,go在linux下超級快,這正是它的設計目標(非常高興它確實如此)

Java和C都有更明確的數據和方法(函數)定義。 C是靜態類型的,其繼承模型的Java較少。 這意味着在編譯期間幾乎定義了數據的處理方式。

Go的數據和函數定義更加隱含。 內置函數本質上更通用,缺少類型層次結構(如Java或C ++)使Go速度不利。

請記住,Google的Go語言目標是在執行速度和編碼速度之間達成可接受的折衷。 我認為他們在早期嘗試中獲得了一個很好的好處,事情只會隨着更多的工作而改善。

如果將Go與更具動態類型的語言進行比較,其主要優點是編碼速度,您將看到Go的執行速度優勢。 在你使用的那些基准測試中,Go比perl快8倍,比Ruby 1.9和Python 3快6倍。

無論如何,更好的問題是在編程的簡易性和執行速度方面做出妥協? 我的回答是肯定的,應該會變得更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM