如期而至,Go1.14釋出了,和往常一樣,該版本保留了Go 1相容性的承若,這個版本的大部分更新在工具鏈 、執行時庫的效能提升方面,總的來說,還是在已有的基礎上不斷優化提成,大家期待的泛型還沒有到來,下面一塊看看新的變化吧,以下變化我本地測試過。
Go 1.14 test 優化
go test -v現在將t.Log輸出流式傳輸,而不是在所有測試資料結束時輸出。
testing包的T、B和TB都加上了CleanUp方法,主要作用可以用來測試結束後清理資源,如下程式碼,輸出結果是 test cleanup, clear resourcce
, 那麼問題來了,如果我在方法中再加一個defer呢,是Cleanup最後執行還是defer最後執行
func TestCleanup(t *testing.T) {
t.Cleanup(func() {
t.Log("clear resource")
})
t.Log("test cleanup")
}
看下面測試程式碼,我們在Cleanup之前和之後都加上defer函式,列印結果如下,我們可以看到,Cleanup還是在defer之後,原理暫時不說了,我也沒研究。
func TestCleanup(t *testing.T) {
defer func() { t.Log("defer resource1") }()
t.Cleanup(func() {
t.Log("clear resource")
})
defer func() { t.Log("defer resource2") }()
t.Log("test cleanup")
}
test cleanup
defer resource2
defer resource1
clear resource
Go 1.14 defer優化
defer與直接呼叫延遲函式相比, 此版本提高了大多數使用的效能,從而產生了幾乎為零的開銷。結果,defer現在可以在對效能至關重要的程式碼中使用,而無需擔心開銷,我們看一下壓測報告
//宣告一個通道
type channel chan string
//正常關閉
func NoDefer() {
ch1 := make(channel, 10)
close(ch1)
}
//採用defer關閉
func Defer() {
ch2 := make(channel, 10)
defer close(ch2)
}
Go1.13 的基準測試報告如下
Go1.14 的基準測試報告如下
關於這一改進,官方給出的迴應是:Go1.14提高了defer的大多數用法的效能,幾乎0開銷!defer已經可以用於對效能要求很高的場景了.
Go1.14 新增了新包maphash
包maphash提供位元組序列的雜湊函式。這些雜湊函式用於實現雜湊表或其他資料結構,這些資料結構需要將任意字串或位元組序列對映到無符號64位整數上的統一分佈,雜湊函式是抗衝突的,但不是加密安全的
func MapHashStudy() {
b := []byte("foo")
h1 := new(maphash.Hash)
h1.Write(b)
//輸出位元組陣列的hash值
fmt.Println(h1.Sum64()) //63175979700884496
}
Go1.14 time.Timer定時器效能得到“巨幅”提升
下圖是官方的一個壓測資料包告,從基準測試的結果可以看出Go1.14 time包中Ticker等函式效能都得到了“巨幅”提升,資料來源如下,我們可以看到Ticker從 5.4ms 提成到了 0.03ms,非常恐怖的
https://github.com/golang/go/commit/6becb033341602f2df9d7c55cc23e64b925bbee2
Go1.14 goroutine支援非同步搶佔
Go語言排程器的效能隨著版本迭代表現的越來越優異,GMP的概念大家應該都知道,不明白了可以百度一下,這裡不說了。
在Go1.1版本中,排程器還不支援搶佔式排程,只能依靠 goroutine 主動讓出 CPU 資源,存在非常嚴重的排程問題。
Go1.12中編譯器在特定時機插入函式,通過函式呼叫作為入口觸發搶佔,實現了協作式的搶佔式排程。但是這種需要函式呼叫主動配合的排程方式存在一些邊緣情況,就比如說下面的例子:
func main() {
runtime.GOMAXPROCS(1)
go func() {
for {
}
}()
time.Sleep(time.Millisecond)
println("OK")
}
上面程式碼中,其中建立一個goroutine並掛起, main goroutine 優先呼叫了 休眠,此時唯一的 P 會轉去執行 for 迴圈所建立的 goroutine,進而 main goroutine 永遠不會再被排程。換一句話說在Go1.14之前,上邊的程式碼永遠不會輸出OK,因為這種協作式的搶佔式排程是不會使一個沒有主動放棄執行權、且不參與任何函式呼叫的goroutine被搶佔。
Go1.14 實現了基於訊號的真搶佔式排程解決了上述問題。Go1.14 程式啟動時, 會在函式runtime.sighandler 中註冊了 SIGURG 訊號的處理函式 runtime.doSigPreempt,在觸發垃圾回收的棧掃描時,呼叫函式掛起goroutine,並向M傳送訊號,M收到訊號後,會讓當前goroutine陷入休眠繼續執行其他的goroutine
Go1.14 生態建設
https://pkg.go.dev 是 go.org的配套網站,裡邊有精選用例和其他資源的資訊,提供了godoc.org 之類的 Go 文件,但它使用起來更方便,並提供了有關軟體包先前版本的資訊,它還可以檢測並顯示許可證,並具有更好的搜尋演算法。
如上圖,是網站的首頁,大家可以進去搜尋一下,看看有沒有新發現。
最後,Go1.14 還有很多改動
- WebAssembly的變化
- reflect包的變化
- go mod的變化
- 很多其他重要的包(math,http等)的改變
很多變化需要大家去探索,本文列出了其中幾個我認為大家必須知道的改變,只是入門,更多原理需要大神們不斷探索,當然我也會盡可能的閱讀原始碼研究。
本作品採用《CC 協議》,轉載必須註明作者和本文連結