go與java

到今天我使用java語言11多年多了,java伴隨我開發了很多服務器項目,伴隨我開發過android,對於java我有比較深厚的感情。我開始關注go是在2017年,那時我就職於某廣告公司,公司的競價系統因爲需要高併發使用go開發。

從2018年開始創業,因爲java非常熟悉,市場上java程序員非常多,方便招聘,首選java開發,從2018下半年開始,毅然決然新的項目使用go開發,是什麼原因讓我下定決心呢?

java的運行原理很簡單,把源文件編譯生成一種二進制中間碼,存儲在class文件中,然後再通過運行與操作系統平臺環境相對應的Java虛擬機來運行class文件,執行編譯產生的字節碼,調用class文件中實現的方法來滿足程序的Java API調用。後續android爲了提升速度出了其他的字節碼文件,和虛擬機不在本次討論範圍
java的前身是1992開發的Oak語言,1996年1月發佈JDK 1.0,1999年4月發佈HotSpot虛擬機,HotSpot成爲了JDK 1.3及之後所有版本的Sun JDK的默認虛擬機

go發佈於2009年,可以說java是20世紀的產物,go是21世紀的產物。跨世紀了[驚!]。

切換

我2008年在學習java的時候還是個學生,是有c和c++基礎的(vc寫過計算機,讀取手機短信這種水平)。 用了3個月的時間才大致弄明白java做的事情。 弄明白了各種關鍵字作用,和麪向對象的機制。實際去企業開發的時候還是會遇到各種問題。而限制使用範圍的關鍵字也只用public和private。很少用連續的繼承。
2018年我帶着團隊學習使用go的時候,只用2周時間大家就都掌握了,能填充代碼開發了。 如果你是一個java程序員,從java到go的距離只有2周時間

開發

// java
@RestController
@RequestMapping(value = "/xx")
public class LotteryController {

    @RequestMapping(value = "/xx1", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    public String xXXX1(HttpServletRequest httpRequest) {
        return "success";
    }
    @RequestMapping(value = "/xx2", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    public String xXXX2(HttpServletRequest httpRequest) {
        return "success";
    }
}

使用iris框架寫個post方法

// go
// 啓動文件
app.Post("/xx/xx1", controller.Xxxx1)
app.Post("/xx/xx2", controller.Xxxx2)
// --------------------------------------
// 具體文件中方法實現
func Xxxx1(ctx context.Context) {
	ctx.Text("success")
}
func Xxxx2(ctx context.Context) {
	ctx.Text("success")
}

這個簡單的例子可以看出 可以看出java spring的方法是註解在實現類中的,go是通過寫在代碼中的更方便。而且所有入口在一個文件中更方便查找。
對於槓精來說可以不用spring註解,使用spring配置文件,或者servlet。。。。
在處理IO時java用try catch finally,finally中還得分開try catch 關閉。我早就忍不了,我都懷疑強迫症的人會無限的寫下去。。。
java啓個線程

new Thread(new Runnable() {
            @Override
            public void run() {
      		// do         
            }
        }).start();

而go的語法就精簡很多了,啓動個協程運行,只要在掉用的時候加關鍵字go。

通過代碼我們可以看出go的代碼非常精簡

運行

go的協程設計確實更適合高併發,java開一個線程就對應於一個系統線程。go開一個協程不對應一個系統線程。一個系統線程內存消耗一般2M,而協程只需要2k。1k個線程是2G內存。2G的內存能放多少協程啊

go的runtime與用戶代碼一起打包成可執行文件,java的代碼需要依賴於虛擬機,open jdk 8的jre有100多Mb呢。

go的協程沒有那麼神祕,可以說實現的很簡單。使用G-P-M模型
G:Goroutine用於存儲運行堆棧、狀態和任務函數可複用,需要綁定到P才能被掉用,Goroutine會排隊等待執行。
P:Processor邏輯處理器,提供執行環境,內存分配狀態,Goroutine隊列等。P的數量由用戶設置的GoMAXPROCS決定,最大數256,P的數量決定了並行執行G隊列的數量。物理CPU核數 >= P的數量
M:Machine 系統內核線程的抽象,代表真正執行的計算資源,在綁定有效的P之後,進入schedule循環,schedule循環機制是P的G隊列中獲取要被執行的G,M的數量由Go RunTime調整,M不保留G的狀態,這樣G在推出M之後,下次可能由其他的M執行
Sched:Go調度器。負責維護G的總隊列,和P中存在的G隊列和狀態信息,創建M,清理回收M等工作

性能測試
是騾子是馬拉出來溜溜
使用ab命令壓測同一臺機器(2C4G 操作是根據id查詢數據庫中的一條記錄) 請求次數100000 線程數150,爲了避免干擾啓動go服務的時候關閉java服務,反之亦然。

java環境: spring boot 2.2.5 + mybatis 3.5.3 hikari連接池 連接數200
tomcat設置:JAVA_OPTS="-Xms256m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=128m"

java第一次
在這裏插入圖片描述
java第二次
在這裏插入圖片描述
java第三次
在這裏插入圖片描述
java第四次
在這裏插入圖片描述
java第五次
在這裏插入圖片描述
java的統計情況
在這裏插入圖片描述

go環境: iris v11.1.1 + gorm v1.9.10

go第一次
在這裏插入圖片描述

go第二次
在這裏插入圖片描述
go第三次
在這裏插入圖片描述
go第四次
在這裏插入圖片描述
go第五次
在這裏插入圖片描述

go的統計情況
在這裏插入圖片描述

說明 通過壓測我們可以看出Java的第一次壓測劣勢非常明顯,java是編譯成class文件, 第一次執行需要通過虛擬機進行類加載,之後的執行可以用加載好的文件執行。所以我去掉java的第一次重新計算了一下平均值

java內存 :tomcat啓動之前機器已使用內存是769M,啓動之後是1.20G,壓測時內存峯值1.35G,後面幾次壓測之後,內存回收,回到1.21G

go內存 :go啓動之前機器已使用內存是768M,啓動之後是775M, 壓測時內存峯值804M,,內存回收,回到784M

數據項 java go
總耗時平均 22.36s 20.77s
每秒處理數 4474 4812
每條處理耗時 33.55ms 31.16ms
傳輸速率 1044k/s 1122k/s
壓測過程中cpu使用率 96%-99% 96%-99%
啓動內存佔用 459Mb 7Mb
壓測過程最高佔用內存 613Mb 36Mb
執行結束後內存佔用 470Mb 16Mb

性能測試部分go完勝

打包編譯速度

我使用的是macOS cpu i5 內存 8G

go 編譯linux下的包用時 <2s
java maven 打war包用時 20s

docker image

構建docker image 的大小與方便程度決定了上線部署的速度
爲了測試都基於ubuntu鏡像

數據項 java go
最終鏡像大小 151M 33.8M
操作步驟 1 添加jre和tomcat
2設置環境變量
3添加war包
添加可執行文件
優化空間 未知 使用scratch基礎鏡像體積更小

2019 發生了什麼

go發佈了兩個版本1.12 和1.13 ,從1.13開始我才覺得go能正常使用了。之前go的使用有些弊端,首先打包就是個麻煩事。1.13版本Go Modules 默認成爲了Golang 官方版本原生的包管理方式,包管理問題算是畫上了一個句號。
還有一件非常重要的大事,之前在國內使用某系包,都會收到牆的影響,大家都是使用github上的源代替官方源,2019go有了官方承認的代理https://goproxy.cn,引包不再成爲問題。

java發佈了jdk12

Shenandoah GC算法,沒發佈在openjdk中。G1優化1(可中斷 mixed GC)G1優化2 (歸還不使用的內存),可以看出官方還是想改進垃圾回收。畢竟靠垃圾回收優化養活了Zing悲哀不悲哀
2019 的雙11 阿里90%的容器都使用了Wisp2,這個Wisp2的最重要的一點就是給java安上了協程。真是笑出眼淚。

後續

java的庫非常全面,也很好用。java程序員非常好招聘。垃圾回收一致被大家詬病,java也一直在這方面努力。
go後發優勢明顯,不過在2019之前因爲牆和包管理的問題,非常難用。go的輪子還沒有造那麼多。不過正在快速補充進來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章