Go 在 2019 年發(fā)布了Go 1.12與Go 1.13。Go 1.13 的大部分變化在于工具鏈、運行時和庫的實現(xiàn)坷虑。時隔半年,Go 1.14 正式發(fā)布埂奈。
和之前的版本一樣迄损,該版本保留了 Go 1 兼容性的承若,這個版本的大部分更新在工具鏈 账磺、運行時庫的性能提升方面芹敌∪叮總的來說,還是在已有的基礎(chǔ)上不斷優(yōu)化提成氏捞,大家期待的泛型還沒有到來碧聪,下面一塊看看新的變化吧。重大的更新如下:
- Go 命令中的 Module 支持現(xiàn)在可以投入生產(chǎn)
- 嵌入具有重疊方法集的接口
- defer 性能改進(jìn)
- goroutine 支持異步搶占
- 工具的變化
- time.Timer 定時器性能大幅提升
Go 命令中的 Module 支持現(xiàn)在可以投入生產(chǎn)
現(xiàn)在液茎,可以在 Go 命令中使用 Module 支持逞姿,以供生產(chǎn)使用,并且鼓勵所有用戶遷移到 Go Module 以進(jìn)行依賴項管理捆等。
嵌入具有重疊方法集的接口
Go 1.14 現(xiàn)在允許嵌入具有重疊方法集的接口:來自嵌入式接口的方法允許與 (嵌入) 接口中已存在的方法擁有相同的名稱和簽名滞造。
在 Go 1.14 之前,如下的定義會編譯報錯楚里。
type ReadWriteCloser interface {
io.ReadCloser
io.WriteCloser
}
因為 io.ReadCloser 和 io.WriteCloser 中 Close 方法重復(fù)了断部。Go 1.14開始允許相同簽名的方法可以內(nèi)嵌入一個接口中。與以前一樣班缎,接口中顯式聲明的方法必須保持唯一性蝴光。
defer 性能改進(jìn)
Go1.14 提高了 defer 的大多數(shù)用法的性能,幾乎 0 開銷达址!defer 已經(jīng)可以用于對性能要求很高的場景了蔑祟。
關(guān)于 defer,在Go 1.13 版本已經(jīng)做了一些的優(yōu)化沉唠,相較于 Go 1.12疆虚,defer 大多數(shù)用法性能提升了 30%。而 Go 1.14 的此次改進(jìn)之后更加高效满葛!
goroutine 支持異步搶占
調(diào)度器使用的 G-M-P 模型径簿。下面是相關(guān)的概念:
- G(Goroutine):goroutine,由關(guān)鍵字 go 創(chuàng)建
- M(Machine):在 Go 中稱為 Machine嘀韧,可以理解為工作線程
- P(Processor): 處理器 P 是線程 M 和 Goroutine 之間的中間層(并不是CPU)
M 必須持有 P 才能執(zhí)行 G 中的代碼篇亭,P有自己本地的一個運行隊列,由可運行的 G 組成锄贷,Go 語言調(diào)度器的工作原理就是處理器P的隊列中選擇隊列頭的 goroutine 放到線程 M 上執(zhí)行译蒂,上圖展示了 線程 M、處理器 P 和 goroutine 的關(guān)系谊却。
每個P維護(hù)的G可能是不均衡的柔昼,調(diào)度器還維護(hù)了一個全局G隊列,當(dāng)P執(zhí)行完本地的G任務(wù)后炎辨,會嘗試從全局隊列中獲取G任務(wù)運行(需要加鎖)捕透,當(dāng)P本地隊列和全局隊列都沒有可運行的任務(wù)時,會嘗試偷取其他P中的G到本地隊列運行(任務(wù)竊取)。
在 Go 1.1 版本中激率,調(diào)度器還不支持搶占式調(diào)度咳燕,只能依靠 goroutine 主動讓出 CPU 資源勿决,存在非常嚴(yán)重的調(diào)度問題:
- 單獨的 goroutine 可以一直占用線程運行乒躺,不會切換到其他的 goroutine,造成饑餓問題
- 垃圾回收需要暫停整個程序(Stop-the-world低缩,STW)嘉冒,如果沒有搶占可能需要等待幾分鐘的時間,導(dǎo)致整個程序無法工作
Go 1.12 中編譯器在特定時機插入函數(shù)咆繁,通過函數(shù)調(diào)用作為入口觸發(fā)搶占讳推,實現(xiàn)了協(xié)作式的搶占式調(diào)度。但是這種需要函數(shù)調(diào)用主動配合的調(diào)度方式存在一些邊緣情況玩般,就比如說下面的例子:
import (
"runtime"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
go func() { //創(chuàng)建一個goroutine并掛起
for {
}
}()
time.Sleep(time.Millisecond) //main goroutine 優(yōu)先調(diào)用了 休眠
println("OK")
}
此時唯一的 P 會轉(zhuǎn)去執(zhí)行 for 循環(huán)所創(chuàng)建的 goroutine银觅,進(jìn)而 main goroutine 永遠(yuǎn)不會再被調(diào)度。換一句話說在Go1.14之前坏为,上邊的代碼永遠(yuǎn)不會輸出 OK究驴。這是因為 Go 1.12 實現(xiàn)的協(xié)作式的搶占式調(diào)度是不會使一個沒有主動放棄執(zhí)行權(quán)、且不參與任何函數(shù)調(diào)用的 goroutine 被搶占匀伏。
Go1.14 通過實現(xiàn)了基于信號的真搶占式調(diào)度解決了上述問題洒忧,這是一個非常大的改動,Go 團(tuán)隊對已有的邏輯進(jìn)行重構(gòu)并為 goroutine 增加新的狀態(tài)和字段來支持搶占够颠。沒有函數(shù)調(diào)用的循環(huán)不再能致使調(diào)度程序死鎖或影響 GC熙侍。 除了 Windows/arm,darwin/arm履磨,js/wasm 和 plan9/* 之外的所有平臺均支持此功能蛉抓。
實施搶占的結(jié)果是,在包括 Linux 和 macOS 系統(tǒng)在內(nèi)的 Unix 系統(tǒng)上剃诅,使用 Go 1.14 構(gòu)建的程序?qū)⒈仁褂迷缙诎姹緲?gòu)建的程序接收更多的信號巷送。這意味著使用諸如 syscall 或 golang.org/x/sys/unix 之類的軟件包的程序?qū)⒖吹礁噍^慢的系統(tǒng)調(diào)用,并出現(xiàn) EINTR 錯誤综苔。這些程序?qū)⒈仨氁阅撤N方式處理那些錯誤惩系,最有可能的循環(huán)是再次嘗試系統(tǒng)調(diào)用。有關(guān)此內(nèi)容的更多信息如筛,請參見用于 Linux 系統(tǒng)的 man 7 signal 或用于其他系統(tǒng)的類似文檔堡牡。
工具的變化
關(guān)于Go1.14中對工具的完善,主要說一下 go mod 和 go test杨刨,Go官方肯定希望開發(fā)者使用官方的包管理工具晤柄,Go1.14 完善了很多功能。
go mod 主要做了以下改進(jìn):
- incompatiable versions:如果模塊的最新版本包含go.mod文件妖胀,則除非明確要求或已經(jīng)要求該版本芥颈,否則go get將不再升級到該模塊的不兼容主要版本惠勒。直接從版本控制中獲取時,go list還會忽略此模塊的不兼容版本爬坑,但如果由代理報告纠屋,則可能包括這些版本。
- go.mod文件維護(hù):除了
go mod tidy
之外的 go 命令不再刪除 require指令盾计,該指令指定了間接依賴版本售担,該版本已由主模塊的其他依賴項隱含。除了go mod tidy
之外的 go 命令不再編輯 go.mod 文件署辉,如果更改只是修飾性的族铆。 - Module下載:在module模式下,go命令支持 SVN 倉庫哭尝,go 命令現(xiàn)在包括來自模塊代理和其他HTTP服務(wù)器的純文本錯誤消息的摘要哥攘。如果錯誤消息是有效的UTF-8,且包含圖形字符和空格材鹦,只會顯示錯誤消息逝淹。
go test -v 現(xiàn)在將 t.Log 輸出流式傳輸,而不是在所有測試數(shù)據(jù)結(jié)束時輸出侠姑。
time.Timer 定時器性能大幅提升
在 Go 1.10 之前的版本中创橄,Go語言使用1個全局的四叉小頂堆維護(hù)所有的timer。由time.after莽红,time.Tick妥畏,net.Conn.SetDeadline和friends所使用的內(nèi)部計時器效率更高,鎖爭用更少安吁,上下文切換更少醉蚁。這是一項性能改進(jìn),不會引起任何用戶可見的更改鬼店。
這邊具體的改進(jìn)网棍,大家可以自行了解下,相對比較復(fù)雜妇智,筆者正在學(xué)習(xí)最新的實現(xiàn)滥玷,后續(xù)專門講這部分內(nèi)容。
小結(jié)
Go 1.14 還有很多其他變更:
- WebAssembly的變化
- reflect包的變化
- 很多其他重要的包(math巍棱,http等)的改變
Go語言的錯誤處理提案獲得了社區(qū)很多人的支持惑畴,但是也有很多人反對,結(jié)論是:Go已經(jīng)放棄了這一提案航徙!這些思想還沒有得到充分的發(fā)展如贷,尤其考慮到更改語言的實現(xiàn)成本時,所以有關(guān)枚舉和不可變類型,Go語言團(tuán)隊最近也是不給予考慮實現(xiàn)的杠袱。
Go1.14 也有一些計劃中但是未完成的工作尚猿,Go1.14 嘗試優(yōu)化頁分配器(page allocator),能夠?qū)崿F(xiàn)在 GOMAXPROCS 值比較大時楣富,顯著減少鎖競爭凿掂。這一改動影響很大,能顯著的提高 Go 并行能力菩彬,也會進(jìn)一步提升 timer 的性能缠劝。但是由于實現(xiàn)起來比較復(fù)雜潮梯,有一些來不及解決的問題骗灶,要 delay 到 Go1.15 完成了。
關(guān)于 Go 1.14 的詳細(xì)發(fā)布日志秉馏,可參見 https://golang.org/doc/go1.14耙旦。