Go 1.13版本在2019.9.3正式發布!國外的Gopher Vincent Blanchon發表了一篇文章《Go: Retrospective》(科學上網閱讀),對Go從1.0版本到1.13版本做了簡要的回顧,這里是那篇文章的譯文。

對于每一位Go開發者來說,Go語言的演化歷程是必須要知道的事情。了解這些橫跨年份發布的大版本的主要變化將有助于Gopher理解Go語言的發展理念以及該語言每個版本的優勢與不足。更多關于特定版本的變更細節,可以參考每個版本對應的Changelog。
Go 1.0 – 2012.3月
伴隨著Go語言的第一個版本,Go的締造者還發布了一份兼容性文檔。該文檔保證未來的Go版本將保持向后兼容性(backward-compatible),即始終兼容已有的代碼,保證已有代碼在Go新版本下編譯和運行的正確性。
Go 1.0版本還包含了go tool pprof命令,這是一個google pprof C++ profiler的變體。Go 1.0還提供了go vet命令(之前的go tool vet),用于報告Go package中可能的錯誤。
Go 1.1 – 2013.5月
該版本主要專注于語言改善和性能提升(編譯器、垃圾回收、map、goroutine調度)。這里是一個改善后的效果示意圖:

圖來自https://dave.cheney.net/2013/05/21/go-11-performance-improvements
這個版本同時還嵌入了一個競態探測器(race detector),這個工具對于Go這種原生并發的語言是十分必要的。在《Race Detector with ThreadSanitizer”》一文中,你可以找到有關race detector的更多詳細信息。
在這個版本中的一個重點變動是Goroutine調度器被重寫了,重寫后的調度器性能大幅提升。
重寫后的Go調度器的設計如下圖:

圖來自 https://rakyll.org/scheduler/
M對應的是操作系統的線程。P表示一個處理器(P的數量不能超過GOMAXPROCS),每個P擁有一個本地goroutine隊列。在1.1版本之前,P這個抽象并不存在。所有goroutine的調度通過全局互斥鎖進行全局級別的管理。這次改進實現了”work-stealing”算法,允許某個P從其他P的隊列中”偷goroutine”:

圖來自 https://rakyll.org/scheduler/
更多關于Go調度器調度原理以及”work-stealing”算法的信息,可以查看Jaana B. Dogan的文章《Go’s work-stealing scheduler》。
Go 1.2 – 2013.12
在該版本中,Go test命令開始支持代碼測試覆蓋率統計了,并且通過go提供的新子命令: go tool cover可以查看代碼測試覆蓋率統計信息:

圖來自 https://blog.golang.org/cover
它還能提供代碼覆蓋信息:

圖來自 https://blog.golang.org/cover
Go 1.3 – 2014.6
該版本包含了棧管理的一個重要改進。在該版本中,棧內存分配采用連續段(contiguous segment)的分配模式以提升內存分配效率。這將為下一個版本將棧size降到2KB奠定基礎。之前的分割棧分配方式(segment stack)存在頻繁分配/釋放棧段導致棧內存分配性能不穩定(較低)的問題,引入新機制后,分配穩定性和性能都有較大改善。
這里是一個json包的例子,圖中顯示json包對棧size的敏感度:

圖來自 contiguous stack
使用連續段的棧內存分配管理模式解決了一些程序性能低下的問題。下面是html/template包的性能對stack size的敏感度圖:

更多信息可參見[《How Does the Goroutine Stack Size Evolve?”》(https://medium.com/@blanchon.vincent/go-how-does-the-goroutine-stack-size-evolve-447fc02085e5)]。
這個版本還發布了sync.Pool。這個組件允許我們后面重用結構體,減少內存分配的次數。它也將成為Go生態圈中許多性能提升的源頭,比如:標準庫中的encoding/json、net/http或是Go社區中的zap等。
關于sync.Pool的更多信息,可以參考文章《Understand the Design of Sync.Pool》。
Go開發組在該版本中對channel進行了優化改善,使其性能獲得提升。下面是channel在Go 1.2和Go 1.3版本中的基準測試數據對比:

Go 1.4 – 2014.12
在該版本中,Go提供了對Android的官方支持。使用golang.org/x/mobile包,gopher們可以使用Go編寫簡單的Android應用。
同時,之前版本中大量用C語言和匯編語言實現的運行時已經被翻譯為Go,一個更為精確的垃圾回收器讓堆內存分配減少了10~30%。
和版本自身無關的是,Go工程在本次發布后已經從Mercurial遷移到Git,從Google code遷移到github。
Go還發布了go generate命令,該命令可以通過掃碼代碼中的//go:generate指示器來生成代碼,可以幫助Gopher簡化代碼生成工作。
更多關于這方面的信息可以參考Go blog和這篇文章《Generating code》。
Go 1.5 – 2015.8
這個新版本推遲了兩個月發布,目的是適應Go新的開發發布周期:每年二月和八月進行發布:

圖來自:https://github.com/golang/go/wiki/Go-Release-Cycle
在該版本中,垃圾回收器被全面重構。由于引入并發回收器,回收階段帶來的延遲大幅減少。下面是來自一個生產環境服務器上的延遲數據,我們看到延遲從300ms降到了30ms:

圖片來自 https://blog.golang.org/ismmkeynote
這個版本還發布go tool trace命令,通過該命令我們可以實現執行器的跟蹤(trace)。這些跟蹤是在test執行、運行時生成的,跟蹤信息可以通過瀏覽器呈現:

圖片來自原始Go Execution Tracer文檔
Go 1.6 – 2016.2
這個版本的最顯著變化是當使用HTTPS時,將默認支持HTTP/2。
垃圾回收器的延遲在該版本中進一步降低:

圖片來自https://blog.golang.org/ismmkeynote
Go 1.7 – 2016.8
這個版本發布了context包。該包用于處理timeout和取消任務。
更多關于context包的信息,可參考文章:《Context and Cancellation by Propagation》。
編譯器工具鏈的性能得到了較大幅度優化,編譯速度更快,二進制文件size更小,有些時候幅度可達20~30%。
Go 1.8 – 2017.2
垃圾回收器的延遲在該版本中進一步改善,延遲時間已經全面降到毫秒級別以下:

圖片來自https://blog.golang.org/ismmkeynote
對延遲的優化還將繼續。接下來版本的目標是將延遲降到100微秒左右。
這個版本還大幅提升了defer的性能:

圖片來自 https://medium.com/@blanchon.vincent/go-how-does-defer-statement-work-1a9492689b6e
更多關于defer的信息,可以參考文章How Does Defer statement Work?。
Go 1.9 – 2017.8
該版本引入了alias語法。
type byte = uint8
這里byte是unit8的一個alias。
sync包增加了Map類型,該類型支持并發訪問(原生map類型不支持)。
關于map的更多信息,參考文章“Concurrency Access with Maps”。
Go 1.10 – 2018.2
在該版本中,test包引入了一個新的緩存機制,所有通過測試的結果都將被緩存下來。當test沒有變化時,重復執行test會節省大量運行test的時間。
first run: ok /go/src/retro 0.027s second run: ok /go/src/retro (cached)
go build命令也維護了一個已構建的包的緩存以加速構建性能。
該版本中垃圾回收器并沒有顯著性能提升。但是Go team為垃圾回收定義了一個新的SLO(Service-Level Objective):

圖片來自https://blog.golang.org/ismmkeynote
Go 1.11 – 2018.8
Go 1.11引入了一個重要的新功能:Go modules。Go module的引入是為了應對過去幾年官方調查問卷結果中Go社區反饋的幾個主要挑戰:

圖片來自 https://blog.golang.org/survey2018-results
另外一個重要功能是一個試驗功能:支持WebAssembly。允許開發人員將Go源碼編譯成一個兼容四個主流瀏覽器的二進制格式文件。
Go 1.12 – 2019.2
該版本中,go vet基于analysis包進行了重寫,使得go vet更為靈活并支持Go開發人員編寫自己的checker。
更多關于analyzer的信息可以參考文章《How to Build Your Own Analyzer》。
Go 1.13 – 2019.9
在該版本中,sync.Pool得到了改善:當垃圾回收時,pool中對象不會被完全清理掉。它引入了一個cache,用于在兩次GC之前清理pool中未使用的對象實例。
逃逸分析(escape analysis)被重新實現了,在該版本中,Go得意更少地在堆上分配內存了。下面是新舊逃逸分析的基準測試對比:

圖片來自 https://github.com/golang/go/issues/23109
英文原文鏈接:https://medium.com/a-journey-with-go/go-retrospective-b9723352e9b0
譯文鏈接:https://tonybai.com/2019/09/07/go-retrospective/
本文譯者:tony bai,bigwhite. 版權所有.