Go 1.13版本在2019.9.3正式發(fā)布!國外的Gopher Vincent Blanchon發(fā)表了一篇文章《Go: Retrospective》(科學上網(wǎng)閱讀),對Go從1.0版本到1.13版本做了簡要的回顧,這里是那篇文章的譯文。
對于每一位Go開發(fā)者來說,Go語言的演化歷程是必須要知道的事情。了解這些橫跨年份發(fā)布的大版本的主要變化將有助于Gopher理解Go語言的發(fā)展理念以及該語言每個版本的優(yōu)勢與不足。更多關(guān)于特定版本的變更細節(jié),可以參考每個版本對應(yīng)的Changelog。
Go 1.0 – 2012.3月
伴隨著Go語言的第一個版本,Go的締造者還發(fā)布了一份兼容性文檔。該文檔保證未來的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調(diào)度)。這里是一個改善后的效果示意圖:
圖來自https://dave.cheney.net/2013/05/21/go-11-performance-improvements
這個版本同時還嵌入了一個競態(tài)探測器(race detector),這個工具對于Go這種原生并發(fā)的語言是十分必要的。在《Race Detector with ThreadSanitizer”》一文中,你可以找到有關(guān)race detector的更多詳細信息。
在這個版本中的一個重點變動是Goroutine調(diào)度器被重寫了,重寫后的調(diào)度器性能大幅提升。
重寫后的Go調(diào)度器的設(shè)計如下圖:
圖來自 https://rakyll.org/scheduler/
M對應(yīng)的是操作系統(tǒng)的線程。P表示一個處理器(P的數(shù)量不能超過GOMAXPROCS),每個P擁有一個本地goroutine隊列。在1.1版本之前,P這個抽象并不存在。所有g(shù)oroutine的調(diào)度通過全局互斥鎖進行全局級別的管理。這次改進實現(xiàn)了”work-stealing”算法,允許某個P從其他P的隊列中”偷goroutine”:
圖來自 https://rakyll.org/scheduler/
更多關(guān)于Go調(diào)度器調(diào)度原理以及”work-stealing”算法的信息,可以查看Jaana B. Dogan的文章《Go’s work-stealing scheduler》。
Go 1.2 – 2013.12
在該版本中,Go test命令開始支持代碼測試覆蓋率統(tǒng)計了,并且通過go提供的新子命令: go tool cover可以查看代碼測試覆蓋率統(tǒng)計信息:
圖來自 https://blog.golang.org/cover
它還能提供代碼覆蓋信息:
圖來自 https://blog.golang.org/cover
Go 1.3 – 2014.6
該版本包含了棧管理的一個重要改進。在該版本中,棧內(nèi)存分配采用連續(xù)段(contiguous segment)的分配模式以提升內(nèi)存分配效率。這將為下一個版本將棧size降到2KB奠定基礎(chǔ)。之前的分割棧分配方式(segment stack)存在頻繁分配/釋放棧段導(dǎo)致棧內(nèi)存分配性能不穩(wěn)定(較低)的問題,引入新機制后,分配穩(wěn)定性和性能都有較大改善。
這里是一個json包的例子,圖中顯示json包對棧size的敏感度:
圖來自 contiguous stack
使用連續(xù)段的棧內(nèi)存分配管理模式解決了一些程序性能低下的問題。下面是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)]。
這個版本還發(fā)布了sync.Pool。這個組件允許我們后面重用結(jié)構(gòu)體,減少內(nèi)存分配的次數(shù)。它也將成為Go生態(tài)圈中許多性能提升的源頭,比如:標準庫中的encoding/json、net/http或是Go社區(qū)中的zap等。
關(guān)于sync.Pool的更多信息,可以參考文章《Understand the Design of Sync.Pool》。
Go開發(fā)組在該版本中對channel進行了優(yōu)化改善,使其性能獲得提升。下面是channel在Go 1.2和Go 1.3版本中的基準測試數(shù)據(jù)對比:
Go 1.4 – 2014.12
在該版本中,Go提供了對Android的官方支持。使用golang.org/x/mobile包,gopher們可以使用Go編寫簡單的Android應(yīng)用。
同時,之前版本中大量用C語言和匯編語言實現(xiàn)的運行時已經(jīng)被翻譯為Go,一個更為精確的垃圾回收器讓堆內(nèi)存分配減少了10~30%。
和版本自身無關(guān)的是,Go工程在本次發(fā)布后已經(jīng)從Mercurial遷移到Git,從Google code遷移到github。
Go還發(fā)布了go generate命令,該命令可以通過掃碼代碼中的//go:generate指示器來生成代碼,可以幫助Gopher簡化代碼生成工作。
更多關(guān)于這方面的信息可以參考Go blog和這篇文章《Generating code》。
Go 1.5 – 2015.8
這個新版本推遲了兩個月發(fā)布,目的是適應(yīng)Go新的開發(fā)發(fā)布周期:每年二月和八月進行發(fā)布:
圖來自:https://github.com/golang/go/wiki/Go-Release-Cycle
在該版本中,垃圾回收器被全面重構(gòu)。由于引入并發(fā)回收器,回收階段帶來的延遲大幅減少。下面是來自一個生產(chǎn)環(huán)境服務(wù)器上的延遲數(shù)據(jù),我們看到延遲從300ms降到了30ms:
圖片來自 https://blog.golang.org/ismmkeynote
這個版本還發(fā)布go tool trace命令,通過該命令我們可以實現(xiàn)執(zhí)行器的跟蹤(trace)。這些跟蹤是在test執(zhí)行、運行時生成的,跟蹤信息可以通過瀏覽器呈現(xiàn):
圖片來自原始Go Execution Tracer文檔
Go 1.6 – 2016.2
這個版本的最顯著變化是當使用HTTPS時,將默認支持HTTP/2。
垃圾回收器的延遲在該版本中進一步降低:
圖片來自https://blog.golang.org/ismmkeynote
Go 1.7 – 2016.8
這個版本發(fā)布了context包。該包用于處理timeout和取消任務(wù)。
更多關(guān)于context包的信息,可參考文章:《Context and Cancellation by Propagation》。
編譯器工具鏈的性能得到了較大幅度優(yōu)化,編譯速度更快,二進制文件size更小,有些時候幅度可達20~30%。
Go 1.8 – 2017.2
垃圾回收器的延遲在該版本中進一步改善,延遲時間已經(jīng)全面降到毫秒級別以下:
圖片來自https://blog.golang.org/ismmkeynote
對延遲的優(yōu)化還將繼續(xù)。接下來版本的目標是將延遲降到100微秒左右。
這個版本還大幅提升了defer的性能:
圖片來自 https://medium.com/@blanchon.vincent/go-how-does-defer-statement-work-1a9492689b6e
更多關(guān)于defer的信息,可以參考文章How Does Defer statement Work?。
Go 1.9 – 2017.8
該版本引入了alias語法。
type byte = uint8
這里byte是unit8的一個alias。
sync包增加了Map類型,該類型支持并發(fā)訪問(原生map類型不支持)。
關(guān)于map的更多信息,參考文章“Concurrency Access with Maps”。
Go 1.10 – 2018.2
在該版本中,test包引入了一個新的緩存機制,所有通過測試的結(jié)果都將被緩存下來。當test沒有變化時,重復(fù)執(zhí)行test會節(jié)省大量運行test的時間。
first run: ok /go/src/retro 0.027s second run: ok /go/src/retro (cached)
go build命令也維護了一個已構(gòu)建的包的緩存以加速構(gòu)建性能。
該版本中垃圾回收器并沒有顯著性能提升。但是Go team為垃圾回收定義了一個新的SLO(Service-Level Objective):
圖片來自https://blog.golang.org/ismmkeynote
Go 1.11 – 2018.8
Go 1.11引入了一個重要的新功能:Go modules。Go module的引入是為了應(yīng)對過去幾年官方調(diào)查問卷結(jié)果中Go社區(qū)反饋的幾個主要挑戰(zhàn):
圖片來自 https://blog.golang.org/survey2018-results
另外一個重要功能是一個試驗功能:支持WebAssembly。允許開發(fā)人員將Go源碼編譯成一個兼容四個主流瀏覽器的二進制格式文件。
Go 1.12 – 2019.2
該版本中,go vet基于analysis包進行了重寫,使得go vet更為靈活并支持Go開發(fā)人員編寫自己的checker。
更多關(guān)于analyzer的信息可以參考文章《How to Build Your Own Analyzer》。
Go 1.13 – 2019.9
在該版本中,sync.Pool得到了改善:當垃圾回收時,pool中對象不會被完全清理掉。它引入了一個cache,用于在兩次GC之前清理pool中未使用的對象實例。
逃逸分析(escape analysis)被重新實現(xiàn)了,在該版本中,Go得意更少地在堆上分配內(nèi)存了。下面是新舊逃逸分析的基準測試對比:
圖片來自 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. 版權(quán)所有.






