java时间比较大小_Go、Java 和 Rust 的比较:得出了挺多结论
最近這幾年,Go、Rust?收到越來越多的關注,特別是 Go,在國內挺受歡迎的,很多大公司都采用它。而 Rust,作為系統編程語言收到越來越多的人關注,蘋果、微軟都宣稱他們使用 Rust 編寫部分業務。而 Java 作為老牌編程語言,長期霸占編程語言排行榜第一或第二位。這篇文章從一些角度就以上三門語言做一個對比。
本文是 Java,Go 和 Rust 之間的比較。但這不是性能測試,主要關注可執行文件大小,內存使用,CPU 使用率,運行時要求等,當然還有一個小的基準測試,看看每秒能處理的請求數,并通過數據展示。
為了更好的進行比較,我使用這三種語言分別編寫了一個 Web 服務。該 Web 服務非常簡單,它為三個 REST 端點提供服務。
Web服務在Java,Go和Rust中提供服務的端點這三個 Web 服務的代碼托管在 GitHub: https://github.com/dexterdarwich/ws-compare 上。
編譯后可執行文件大小
關于如何構建二進制文件。在 Java 中,我已經使用 maven-shade-plugin 將所有內容構建到一個大的 jar 中,并使用了 mvn packagetarget。對于 Go,我使用 go build。而對于 Rust,我使用 build --release。
每個程序的編譯大小(以 Mb 為單位)編譯后的大小還取決于所選的庫/依賴項。在本文中,對于我選擇的庫,以上是程序的編譯大小。
在后面,我將把這三個程序構建并打包為 Docker 映像,同時列出它們的大小,以顯示每種語言所需的運行時開銷。下面有更多詳細信息。
內存使用
空閑時的內存使用
每個應用程序在內存空閑時的內存使用情況什么?Go 和 Rust 版本的條形圖在哪里顯示空閑時的內存占用量?好了,它們在那里,只有當 JVM 啟動程序并處于空閑狀態時,Java 才消耗 160 MB 以上的內存,這時什么也沒做。對于 Go,程序使用 0.86 MB,對于Rust,則使用 0.36 ?MB。這是一個很大的差異!在這里,Java 使用的內存比 Go 和 Rust 對應的內存高兩個數量級,什么都沒做就耗這么多內存,是巨大的資源浪費。
服務 Rest 請求
讓我們使用 wrk 通過請求訪問 API,并觀察內存和 CPU 使用情況,以及在我的計算機上針對程序的三個版本的每個端點每秒實現的請求數。
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 個打開的連接,并重復使用 GET 方式訪問端點,持續 30 秒。這里我僅使用兩個線程,因為 wrk 和被測程序都在同一臺計算機上運行,所以我不希望它們在可用資源(尤其是 CPU)上相互競爭(太多)。
每個 Web 服務都經過單獨測試,并且在每次運行之間都重新啟動了 Web 服務。
以下是該程序的每個版本的三個運行中的最佳結果。
/hello
該端點返回 Hello,World!信息。它生成字符串 “ Hello,World!” 將其序列化并以 JSON 格式返回。
訪問hello端點時的CPU使用率請求hello端點時的內存使用情況請求hello端點時的每秒請求數/greeting/{name}
該端點接受路徑參數{name},然后格式化字符串 “ Hello,{name}!”,進行序列化并將其返回為 JSON 格式的問候消息。
請求greeting端點時的CPU使用率請求greeting端點時的內存使用情況請求greeting端點時的每秒請求數/fibonacci/{number}
該端點接受路徑路參數 {number},并返回斐波納契數列并序列化為 JSON 格式。
這個特定的端點我選擇以遞歸形式實現它。毫不懷疑,循環方式實現會產生更好的性能結果,并且出于生產目的,應該選擇一種迭代形式,但是在生產代碼中,有些情況下必須使用遞歸(并非專門用于計算第 n 個斐波那契數))。因此,我希望實現大量涉及 CPU、棧內存分配。
請求fibonacci端點時的CPU使用率請求fibonacci端點時的內存使用情況請求fibonacci端點時的每秒請求數在 Fibonacci 端點測試中,Java 實現是唯一一個有 150 個請求出現了超時, wrk 的輸出如下所示。
fibonacci端點的時延運行時大小
為了模擬現實世界中的云原生應用程序,并消除“它可以在我的機器上運行!”,我為這三個應用程序中的每一個創建了一個 Docker 映像。
Docker 文件的源包含在相應程序文件夾下的代碼庫中。
作為 Java 應用程序的基本運行時鏡像,我使用了 openjdk:8-jre-alpine,該鏡像被稱為是最小的鏡像之一,但是,它附帶了一些警告,這些警告可能適用于你的應用程序,也可能不適用于你的應用程序,主要是 alpine 鏡像在處理環境變量名稱方面不符合 posix,因此在 Docker 文件中,你不能使用 . 字符,另一方面是 alpine Linux 鏡像是使用 musl libc 而不是 glibc 編譯的,這意味著如果你的應用程序依賴需要 glibc,它將無法正常工作。在我這個例子,alpine 可以正常運行。
至于應用程序的 Go 版本和 Rust 版本,我已經對其進行了靜態編譯,這意味著它們不希望在運行時鏡像中存在libc(glibc,musl…等),這也意味著它們不需要運行 OS 的基本映像。因此,我使用了臨時 docker 映像,這是一個無操作映像,以零開銷托管已編譯的可執行文件。
我使用的 Docker 映像的命名約定為 {lang}/webservice。該應用程序的 Java,Go 和 Rust 版本的鏡像大小分別為 113、8.68 和 4.24 MB。
最終Docker映像大小結論
三種語言的比較在得出任何結論之前,我想指出這三種語言之間的關系。Java 和 Go 都是垃圾收集語言,但是 Java 會提前編譯(AOT)為在 JVM 上運行的字節碼。當啟動 Java 應用程序時,即時(JIT)編譯器將被調用,以通過隨時隨地將其編譯為本機代碼來優化字節碼,以提高應用程序的性能。
Go 和 Rust 都提前編譯為本地代碼,并且在運行時不會進行進一步的優化。
Java 和 Go 都是垃圾收集語言,有 Stop-The-World 的副作用。這意味著,每當垃圾收集器運行時,它將停止應用程序,進行垃圾收集,并在完成后從停止的地方恢復應用程序。大多數垃圾收集器需要停止運行,但是有些實現似乎不需要這樣做。
Java 語言是 90 年代創建的,其最大的賣點之一是一次編寫,可在任何地方運行。當時,這很棒,因為市場上沒有很多虛擬化解決方案。如今,各種虛擬化技術存在,特別是 Docker 和其他解決方案以便宜的價格提供虛擬化,使得跨平臺不再那么稀奇。
在整個測試中,應用程序的 Java 版本比 Go 或 Rust 對應版本消耗了更多的內存,在前兩個測試中,Java 使用的內存大約增加了 8000%。這意味著對于實際應用程序,Java 應用程序的運行成本會更高。
對于前兩個測試,Go 應用程序使用的 CPU 比 Java 少 20%,而處理的請求卻增加 38%。另一方面,Rust 版本使用的 CPU 比 Go 減少了 57%,而處理的請求卻增加了 13%。
第三次測試在設計上是占用大量 CPU 的資源,因此我想從中壓榨 CPU。Go 和 Rust 都比 Java 多使用了 1% 的 CPU。而且我認為,如果 wrk 不在同一臺計算機上運行,則所有這三個版本都會使 CPU 上限達到 100%。在內存方面,Java 使用的內存比 Go 和 Rust 多 2000%。Java 可以處理的請求比 Go 多出 20%,而 Rust 可以處理的請求比 Java 多出 15%。
在撰寫本文時,Java 編程語言已經存在了將近 30 年,這使得在市場上尋找 Java 開發人員變得相對容易。另一方面,Go 和 Rust 都是相對較新的語言,因此與 Java 相比,自然而然開發人員更少。不過,Go 和 Rust 都獲得了很大的吸引力,許多開發人員正在將它們用于新項目,并且有許多在生產環境使用 Go 和 Rust 的項目或公司,因為簡單地說,就資源而言,它們比 Java 更有效。(也許是因為它們是新的、酷的語言!)
在編寫本文的程序時,我同時學習了 Go 和 Rust。就我而言,Go 的學習曲線很平滑,因為它是一種相對容易掌握的語言,并且與其他語言相比語法很少。我只用了幾天就用 Go 編寫了程序。關于 Go 需要注意的一件事是編譯速度,我不得不承認,與 Java/C/C++/Rust 等其他語言相比,它的速度非常快。該程序的 Rust 版本花了我大約一個星期的時間來完成,我不得不說,大部分時間都花在弄清借閱檢查器(borrow checker)向我要什么上。Rust 具有嚴格的所有權規則,但是一旦掌握了 Rust 的所有權和借用(borrowing)概念,編譯器錯誤消息就會突然變得更加有意義。當違反借閱檢查規則時,Rust 編譯器對您大吼大叫的原因是,因為編譯器要在編譯時證明已分配內存的壽命和所有權。這樣,它保證了程序的安全性(例如:除非使用了不安全的代碼轉義,否則就沒有懸掛指針),并且在編譯時確定了釋放位置,從而消除了垃圾收集器的需求和運行時成本。當然,這是以學習 Rust 的所有權系統為代價的。
在競爭方面,我認為 Go 是 Java(通常是 JVM 語言)的直接競爭對手,但不是 Rust 的競爭對手。另一方面,Rust 是Java,Go,C 和 C++ 的重要競爭對手。(注:感覺 Rust 好猛呀!)
由于它們的效率,我想到了自己。并且將會用 Go 和 Rust 編寫更多的程序,但是很可能用 Rust 編寫更多的程序。兩者都非常適合網絡服務,CLI,系統程序等的開發。但是,Rust 比 Go 具有根本優勢。它不是垃圾收集的語言,與 C 和 C++ 相比,它可以安全地編寫代碼。例如,Go 并不是特別適合用于編寫 OS 內核,而這里又是 Rust 的亮點,并與 C/C++ 競爭,因為它們是使用 OS 編寫的長期存在和事實上的語言。Rust 與 ?C/C++ 競爭的另一種方式是在嵌入式世界中,但我將后續進行討論。
最后簡單介紹下 Rust 語言:
Rust 是一門系統編程語言,專注于安全,尤其是并發安全,支持函數式和命令式以及泛型等編程范式的多范式語言。Rust 在語法上和 C++ 類似,但是設計者想要在保證性能的同時提供更好的內存安全。Rust 最初是由 Mozilla 研究院的 Graydon Hoare 設計創造,然后在 Dave Herman, Brendan Eich以 及很多其他人的貢獻下逐步完善的。Rust的設計者們通過在研發 Servo 網站瀏覽器布局引擎過程中積累的經驗優化了 Rust 語言和 Rust編譯器。
Rust編譯器是在 MIT License 和 Apache License 2.0 雙重協議聲明下的免費開源軟件。Rust 已經連續四年(2016,2017,2018,2019)在 Stack Overflow 開發者調查的“最受喜愛編程語言”評選項目中折取桂冠。
本公眾號觀點:語言沒有絕對好壞,只有適合不適合。
原文鏈接:https://medium.com/@dexterdarwich/comparison-between-java-go-and-rust-fdb21bd5fb7c
作者:Dexter Darwich
關注我
大家也可以關注我的公眾號《腦洞前端》獲取更多更新鮮的前端硬核文章,帶你認識你不知道的前端。
總結
以上是生活随笔為你收集整理的java时间比较大小_Go、Java 和 Rust 的比较:得出了挺多结论的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: phonegap在android中如何退
- 下一篇: 解析mediaTypes+viewRes