<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go、Java 和 Rust 的比較:得出了挺多結(jié)論

          共 5149字,需瀏覽 11分鐘

           ·

          2020-11-25 04:38


          點擊上方藍(lán)色“火丁筆記”關(guān)注我們,設(shè)個星標(biāo),每天學(xué)習(xí)全棧知識

          最近這幾年,Go、Rust?收到越來越多的關(guān)注,特別是 Go,在國內(nèi)挺受歡迎的,很多大公司都采用它。而 Rust,作為系統(tǒng)編程語言收到越來越多的關(guān)注,蘋果、微軟都宣稱他們使用 Rust 編寫部分業(yè)務(wù)。而 Java 作為老牌編程語言,長期霸占編程語言排行榜第一或第二位。這篇文章從一些角度就以上三門語言做一個對比。

          本文是 Java,Go 和 Rust 之間的比較。但這不是性能測試,主要關(guān)注可執(zhí)行文件大小,內(nèi)存使用,CPU 使用率,運行時要求等,當(dāng)然還有一個小的基準(zhǔn)測試,看看每秒能處理的請求數(shù),并通過數(shù)據(jù)展示。

          為了更好的進(jìn)行比較,我使用這三種語言分別編寫了一個 Web 服務(wù)。該 Web 服務(wù)非常簡單,它為三個 REST 端點提供服務(wù)。

          Web服務(wù)在Java,Go和Rust中提供服務(wù)的端點

          這三個 Web 服務(wù)的代碼托管在 GitHub: https://github.com/dexterdarwich/ws-compare 上。

          編譯后可執(zhí)行文件大小

          關(guān)于如何構(gòu)建二進(jìn)制文件。在 Java 中,我已經(jīng)使用 maven-shade-plugin 將所有內(nèi)容構(gòu)建到一個大的 jar 中,并使用了 mvn packagetarget。對于 Go,我使用 go build。而對于 Rust,我使用 build --release。

          每個程序的編譯大小(以 Mb 為單位)

          編譯后的大小還取決于所選的庫/依賴項。在本文中,對于我選擇的庫,以上是程序的編譯大小。

          在后面,我將把這三個程序構(gòu)建并打包為 Docker 映像,同時列出它們的大小,以顯示每種語言所需的運行時開銷。下面有更多詳細(xì)信息。

          內(nèi)存使用

          空閑時的內(nèi)存使用

          每個應(yīng)用程序在內(nèi)存空閑時的內(nèi)存使用情況

          什么?Go 和 Rust 版本的條形圖在哪里顯示空閑時的內(nèi)存占用量?好了,它們在那里,只有當(dāng) JVM 啟動程序并處于空閑狀態(tài)時,Java 才消耗 160 MB 以上的內(nèi)存,這時什么也沒做。對于 Go,程序使用 0.86 MB,對于Rust,則使用 0.36 ?MB。這是一個很大的差異!在這里,Java 使用的內(nèi)存比 Go 和 Rust 對應(yīng)的內(nèi)存高兩個數(shù)量級,什么都沒做就耗這么多內(nèi)存,是巨大的資源浪費。

          服務(wù) Rest 請求

          讓我們使用 wrk 通過請求訪問 API,并觀察內(nèi)存和 CPU 使用情況,以及在我的計算機(jī)上針對程序的三個版本的每個端點每秒實現(xiàn)的請求數(shù)。

          wrk?-t2?-c400?-d30s?http://127.0.0.1:8080/hello?
          wrk?-t2?-c400?-d30s?http://127.0.0.1:8080/greeting/Jane
          wrk?-t2?-c400?-d30s?http://127.0.0.1:8080/fibonacci/35

          上面的 wrk 命令表示:使用兩個線程(用于 wrk)并在池中保留 400 個打開的連接,并重復(fù)使用 GET 方式訪問端點,持續(xù) 30 秒。這里我僅使用兩個線程,因為 wrk 和被測程序都在同一臺計算機(jī)上運行,所以我不希望它們在可用資源(尤其是 CPU)上相互競爭(太多)。

          每個 Web 服務(wù)都經(jīng)過單獨測試,并且在每次運行之間都重新啟動了 Web 服務(wù)。

          以下是該程序的每個版本的三個運行中的最佳結(jié)果。

          /hello

          該端點返回 Hello,World!信息。它生成字符串 “ Hello,World!” 將其序列化并以 JSON 格式返回。

          訪問hello端點時的CPU使用率
          請求hello端點時的內(nèi)存使用情況
          請求hello端點時的每秒請求數(shù)

          /greeting/{name}

          該端點接受路徑參數(shù){name},然后格式化字符串 “ Hello,{name}!”,進(jìn)行序列化并將其返回為 JSON 格式的問候消息。

          請求greeting端點時的CPU使用率
          請求greeting端點時的內(nèi)存使用情況
          請求greeting端點時的每秒請求數(shù)

          /fibonacci/{number}

          該端點接受路徑路參數(shù) {number},并返回斐波納契數(shù)列并序列化為 JSON 格式。

          這個特定的端點我選擇以遞歸形式實現(xiàn)它。毫不懷疑,循環(huán)方式實現(xiàn)會產(chǎn)生更好的性能結(jié)果,并且出于生產(chǎn)目的,應(yīng)該選擇一種迭代形式,但是在生產(chǎn)代碼中,有些情況下必須使用遞歸(并非專門用于計算第 n 個斐波那契數(shù)))。因此,我希望實現(xiàn)大量涉及 CPU、棧內(nèi)存分配。

          請求fibonacci端點時的CPU使用率
          請求fibonacci端點時的內(nèi)存使用情況
          請求fibonacci端點時的每秒請求數(shù)

          在 Fibonacci 端點測試中,Java 實現(xiàn)是唯一一個有 150 個請求出現(xiàn)了超時, wrk 的輸出如下所示。

          fibonacci端點的時延

          運行時大小

          為了模擬現(xiàn)實世界中的云原生應(yīng)用程序,并消除“它可以在我的機(jī)器上運行!”,我為這三個應(yīng)用程序中的每一個創(chuàng)建了一個 Docker 映像。

          Docker 文件的源包含在相應(yīng)程序文件夾下的代碼庫中。

          作為 Java 應(yīng)用程序的基本運行時鏡像,我使用了 openjdk:8-jre-alpine,該鏡像被稱為是最小的鏡像之一,但是,它附帶了一些警告,這些警告可能適用于你的應(yīng)用程序,也可能不適用于你的應(yīng)用程序,主要是 alpine 鏡像在處理環(huán)境變量名稱方面不符合 posix,因此在 Docker 文件中,你不能使用 . 字符,另一方面是 alpine Linux 鏡像是使用 musl libc 而不是 glibc 編譯的,這意味著如果你的應(yīng)用程序依賴需要 glibc,它將無法正常工作。在我這個例子,alpine 可以正常運行。

          至于應(yīng)用程序的 Go 版本和 Rust 版本,我已經(jīng)對其進(jìn)行了靜態(tài)編譯,這意味著它們不希望在運行時鏡像中存在libc(glibc,musl…等),這也意味著它們不需要運行 OS 的基本映像。因此,我使用了臨時 docker 映像,這是一個無操作映像,以零開銷托管已編譯的可執(zhí)行文件。

          我使用的 Docker 映像的命名約定為 {lang}/webservice。該應(yīng)用程序的 Java,Go 和 Rust 版本的鏡像大小分別為 113、8.68 和 4.24 MB。

          最終Docker映像大小

          結(jié)論

          三種語言的比較

          在得出任何結(jié)論之前,我想指出這三種語言之間的關(guān)系。Java 和 Go 都是垃圾收集語言,但是 Java 會提前編譯(AOT)為在 JVM 上運行的字節(jié)碼。當(dāng)啟動 Java 應(yīng)用程序時,即時(JIT)編譯器將被調(diào)用,以通過隨時隨地將其編譯為本機(jī)代碼來優(yōu)化字節(jié)碼,以提高應(yīng)用程序的性能。

          Go 和 Rust 都提前編譯為本地代碼,并且在運行時不會進(jìn)行進(jìn)一步的優(yōu)化。

          Java 和 Go 都是垃圾收集語言,有 Stop-The-World 的副作用。這意味著,每當(dāng)垃圾收集器運行時,它將停止應(yīng)用程序,進(jìn)行垃圾收集,并在完成后從停止的地方恢復(fù)應(yīng)用程序。大多數(shù)垃圾收集器需要停止運行,但是有些實現(xiàn)似乎不需要這樣做。

          Java 語言是 90 年代創(chuàng)建的,其最大的賣點之一是一次編寫,可在任何地方運行。當(dāng)時,這很棒,因為市場上沒有很多虛擬化解決方案。如今,各種虛擬化技術(shù)存在,特別是 Docker 和其他解決方案以便宜的價格提供虛擬化,使得跨平臺不再那么稀奇。

          在整個測試中,應(yīng)用程序的 Java 版本比 Go 或 Rust 對應(yīng)版本消耗了更多的內(nèi)存,在前兩個測試中,Java 使用的內(nèi)存大約增加了 8000%。這意味著對于實際應(yīng)用程序,Java 應(yīng)用程序的運行成本會更高。

          對于前兩個測試,Go 應(yīng)用程序使用的 CPU 比 Java 少 20%,而處理的請求卻增加 38%。另一方面,Rust 版本使用的 CPU 比 Go 減少了 57%,而處理的請求卻增加了 13%。

          第三次測試在設(shè)計上是占用大量 CPU 的資源,因此我想從中壓榨 CPU。Go 和 Rust 都比 Java 多使用了 1% 的 CPU。而且我認(rèn)為,如果 wrk 不在同一臺計算機(jī)上運行,則所有這三個版本都會使 CPU 上限達(dá)到 100%。在內(nèi)存方面,Java 使用的內(nèi)存比 Go 和 Rust 多 2000%。Java 可以處理的請求比 Go 多出 20%,而 Rust 可以處理的請求比 Java 多出 15%。

          在撰寫本文時,Java 編程語言已經(jīng)存在了將近 30 年,這使得在市場上尋找 Java 開發(fā)人員變得相對容易。另一方面,Go 和 Rust 都是相對較新的語言,因此與 Java 相比,自然而然開發(fā)人員更少。不過,Go 和 Rust 都獲得了很大的吸引力,許多開發(fā)人員正在將它們用于新項目,并且有許多在生產(chǎn)環(huán)境使用 Go 和 Rust 的項目或公司,因為簡單地說,就資源而言,它們比 Java 更有效。(也許是因為它們是新的、酷的語言!)

          在編寫本文的程序時,我同時學(xué)習(xí)了 Go 和 Rust。就我而言,Go 的學(xué)習(xí)曲線很平滑,因為它是一種相對容易掌握的語言,并且與其他語言相比語法很少。我只用了幾天就用 Go 編寫了程序。關(guān)于 Go 需要注意的一件事是編譯速度,我不得不承認(rèn),與 Java/C/C++/Rust 等其他語言相比,它的速度非???。該程序的 Rust 版本花了我大約一個星期的時間來完成,我不得不說,大部分時間都花在弄清借閱檢查器(borrow checker)向我要什么上。Rust 具有嚴(yán)格的所有權(quán)規(guī)則,但是一旦掌握了 Rust 的所有權(quán)和借用(borrowing)概念,編譯器錯誤消息就會突然變得更加有意義。當(dāng)違反借閱檢查規(guī)則時,Rust 編譯器對您大吼大叫的原因是,因為編譯器要在編譯時證明已分配內(nèi)存的壽命和所有權(quán)。這樣,它保證了程序的安全性(例如:除非使用了不安全的代碼轉(zhuǎn)義,否則就沒有懸掛指針),并且在編譯時確定了釋放位置,從而消除了垃圾收集器的需求和運行時成本。當(dāng)然,這是以學(xué)習(xí) Rust 的所有權(quán)系統(tǒng)為代價的。

          在競爭方面,我認(rèn)為 Go 是 Java(通常是 JVM 語言)的直接競爭對手,但不是 Rust 的競爭對手。另一方面,Rust 是Java,Go,C 和 C++ 的重要競爭對手。(注:感覺 Rust 好猛呀!)

          由于它們的效率,我想到了自己。并且將會用 Go 和 Rust 編寫更多的程序,但是很可能用 Rust 編寫更多的程序。兩者都非常適合網(wǎng)絡(luò)服務(wù),CLI,系統(tǒng)程序等的開發(fā)。但是,Rust 比 Go 具有根本優(yōu)勢。它不是垃圾收集的語言,與 C 和 C++ 相比,它可以安全地編寫代碼。例如,Go 并不是特別適合用于編寫 OS 內(nèi)核,而這里又是 Rust 的亮點,并與 C/C++ 競爭,因為它們是使用 OS 編寫的長期存在和事實上的語言。Rust 與 ?C/C++ 競爭的另一種方式是在嵌入式世界中,但我將后續(xù)進(jìn)行討論。

          最后簡單介紹下 Rust 語言:

          Rust 是一門系統(tǒng)編程語言,專注于安全,尤其是并發(fā)安全,支持函數(shù)式和命令式以及泛型等編程范式的多范式語言。Rust 在語法上和 C++ 類似,但是設(shè)計者想要在保證性能的同時提供更好的內(nèi)存安全。Rust 最初是由 Mozilla 研究院的 Graydon Hoare 設(shè)計創(chuàng)造,然后在 Dave Herman, Brendan Eich以 及很多其他人的貢獻(xiàn)下逐步完善的。Rust的設(shè)計者們通過在研發(fā) Servo 網(wǎng)站瀏覽器布局引擎過程中積累的經(jīng)驗優(yōu)化了 Rust 語言和 Rust編譯器。


          Rust編譯器是在 MIT License 和 Apache License 2.0 雙重協(xié)議聲明下的免費開源軟件。Rust 已經(jīng)連續(xù)四年(2016,2017,2018,2019)在 Stack Overflow 開發(fā)者調(diào)查的“最受喜愛編程語言”評選項目中折取桂冠。

          本公眾號觀點:語言沒有絕對好壞,只有適合不適合。

          原文鏈接:https://medium.com/@dexterdarwich/comparison-between-java-go-and-rust-fdb21bd5fb7c

          作者:Dexter Darwich


          關(guān)注我

          大家也可以關(guān)注我的公眾號《腦洞前端》獲取更多更新鮮的前端硬核文章,帶你認(rèn)識你不知道的前端。


          瀏覽 71
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色AV天堂 | 亚洲私人影院日韩 | 在线观看国产亚洲 | 成人91久久 | 成人AⅤ |