Go 1.16 新功能特性不完全前瞻

bigwhite-github發表於2020-12-12

Go 1.16 將於 2021 年 2 月釋出。目前已經進入 freeze 狀態,即不再接受新 feature,僅 fix bug、編寫文件和接受安全更新等。

目前 Go 1.16 的釋出說明尚處於早期草稿階段,但 Go 團隊成員正在致力於編寫釋出說明。Go 1.16 的完全特性列表說明還得等真正釋出前才能得到。如今要了解 Go 1.16 功能特性都有哪些變化,只能結合現有的 release note 以及從Go 1.16 里程碑中的 issue 列表中挖掘。

下面就 “挖掘” 到的 Go 1.16 重要功能特性變化做簡要的且不完全的前瞻。

1. 支援 Apple Silicon M1 晶片

Apple Silicon M1 晶片 Macbook 的釋出讓 Go 團隊緊急為 Go 1.16 增加對 M1 的支援。如果要跨平臺編譯,只需設定 GOOS=darwin, GOARCH=arm64 即可構建出可以在搭載 M1 晶片的 Macbook 上執行的 Go 應用。

同時 Go 1.16 還增加了對 ios/amd64 的支援,主要是為了支援在 amd64 架構上的 MacOS 上執行 ios 模擬器。

2. RISC-V 架構支援 cgo 和-buildmode=pie

RISC-V 架構很可能是未來 5-10 年挑戰 ARM 的最主要架構,Go 語言持續加大對 RISC-V 架構的支援,在 Go 1.16 中對 linux/riscv64 又增加了 cgo 支援以及-buildmode=pie。不過目前對 risc-v 仍僅限於 linux os。

3. 有關 go module 的變化

  • module-aware 模式成為預設狀態。如要回到 gopath mode,將 GO111MODULE 設定為 auto;
  • go build 和 go test 不會修改 go.mod 和 go.sum 檔案。能修改這兩個檔案的命令只有 go get 和 go mod tidy;
  • go get 之前的構建和安裝 go 包的行為模式將被廢棄。go get 將專注於分析依賴,並獲取 go 包/module,更新 go.mod/go.sum;
  • go install 將恢復自己構建和安裝包的 “角色”(在 go module 加入後,go install 日益受到冷落,這次翻身了);
  • go.mod 將支援 retract 指示符,包或 module 作者可以利用該指示符在自己 module 的 go.mod 中標記某些版本撤回 (因不安全、不相容或損壞等原因),不建議使用。
  • go.mod 中的 exclude 指示符語義變更:Go 1.16 中將忽略 exclude 指示的 module/包依賴;而之前的版本 go 工具鏈僅僅是跳過 exclude 指示的版本,而使用該依賴包/module 的下一個版本。
  • -i build flag 廢棄;
  • go get 的-insecure 命令列標誌選項作廢,可以用 GOINSECURE 環境變數指示 go get 是否通過不安全的 http 去獲取包;

4. 支援在 Go 二進位制檔案中嵌入靜態檔案 (文字、圖片等)

Go 1.16 新增go:embed指示符和 embed 標準庫包,二者一起用於支援在在 Go 二進位制檔案中嵌入靜態檔案。下面是一個在 Go 應用中嵌入文字檔案用於 http 應答內容的小例子:

// hello.txt
hello, go 1.16

// main.go
package main

import (
         _  "embed"
    "net/http"
)

//go:embed hello.txt
var s string

func main() {
    http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte(s))
    }))
    http.ListenAndServe(":8080", nil)
}

上述原始碼中的go:embed指示符的含義是:將 hello.txt 內容儲存在字串變數 s 中。我們構建該原始碼,並驗證一下 s 中儲存的是否是 hello.txt 中的資料:

$ go build -o demo main.go
$ mv hello.txt hello.txt.bak // 將hello.txt改名,我們看看資料是否真的已經嵌入到二進位制檔案demo中了
$ ./demo

$curl localhost:8080
hello, go 1.16

5.GODEBUG 環境變數支援跟蹤

當 GODEBUG 環境變數包含 inittrace=1 時,Go 執行時將會報告各個原始碼檔案中的 init 函式的執行時間和記憶體開闢消耗情況。比如對於上面的程式 demo,我們按如下命令執行:

# GODEBUG=inittrace=1 ./demo
init internal/bytealg @0.014 ms, 0 ms clock, 0 bytes, 0 allocs
init runtime @0.033 ms, 0.015 ms clock, 0 bytes, 0 allocs
init errors @0.24 ms, 0.003 ms clock, 0 bytes, 0 allocs
init sync @0.47 ms, 0.001 ms clock, 16 bytes, 1 allocs
init io @0.66 ms, 0 ms clock, 144 bytes, 9 allocs
init internal/oserror @0.85 ms, 0 ms clock, 80 bytes, 5 allocs
init syscall @1.0 ms, 0.006 ms clock, 624 bytes, 2 allocs
init time @1.2 ms, 0.013 ms clock, 384 bytes, 8 allocs
init path @1.4 ms, 0.003 ms clock, 16 bytes, 1 allocs
init io/fs @1.6 ms, 0 ms clock, 16 bytes, 1 allocs
init context @2.3 ms, 0.002 ms clock, 128 bytes, 4 allocs
init math @2.5 ms, 0 ms clock, 0 bytes, 0 allocs
init strconv @2.7 ms, 0 ms clock, 32 bytes, 2 allocs
init unicode @2.9 ms, 0.065 ms clock, 23736 bytes, 26 allocs
init bytes @3.2 ms, 0 ms clock, 48 bytes, 3 allocs
init crypto @3.3 ms, 0.001 ms clock, 160 bytes, 1 allocs
init reflect @3.5 ms, 0.002 ms clock, 0 bytes, 0 allocs
init encoding/binary @3.7 ms, 0 ms clock, 16 bytes, 1 allocs
init crypto/cipher @3.8 ms, 0 ms clock, 16 bytes, 1 allocs
init crypto/aes @4.0 ms, 0.003 ms clock, 16 bytes, 1 allocs
init internal/poll @4.1 ms, 0 ms clock, 64 bytes, 4 allocs
init os @4.2 ms, 0.029 ms clock, 544 bytes, 13 allocs
init fmt @4.4 ms, 0.003 ms clock, 32 bytes, 2 allocs
init math/rand @4.5 ms, 0.023 ms clock, 5440 bytes, 3 allocs
init math/big @4.7 ms, 0.002 ms clock, 32 bytes, 2 allocs
init crypto/sha512 @4.8 ms, 0.004 ms clock, 0 bytes, 0 allocs
init encoding/asn1 @5.0 ms, 0.004 ms clock, 224 bytes, 7 allocs
init vendor/golang.org/x/crypto/cryptobyte @5.1 ms, 0 ms clock, 48 bytes, 2 allocs
init crypto/ecdsa @5.3 ms, 0 ms clock, 48 bytes, 3 allocs
init bufio @5.4 ms, 0.003 ms clock, 176 bytes, 11 allocs
init crypto/rand @5.6 ms, 0.001 ms clock, 120 bytes, 4 allocs
init crypto/rsa @5.7 ms, 0.007 ms clock, 648 bytes, 18 allocs
init crypto/sha1 @5.8 ms, 0 ms clock, 0 bytes, 0 allocs
init crypto/sha256 @5.9 ms, 0 ms clock, 0 bytes, 0 allocs
init encoding/base64 @5.9 ms, 0.006 ms clock, 1408 bytes, 4 allocs
init crypto/md5 @6.0 ms, 0 ms clock, 0 bytes, 0 allocs
init encoding/hex @6.1 ms, 0 ms clock, 16 bytes, 1 allocs
init crypto/x509/pkix @6.1 ms, 0.001 ms clock, 624 bytes, 2 allocs
init path/filepath @6.2 ms, 0 ms clock, 16 bytes, 1 allocs
init vendor/golang.org/x/net/dns/dnsmessage @6.3 ms, 0.009 ms clock, 1616 bytes, 27 allocs
init net @6.3 ms, 0.029 ms clock, 2840 bytes, 74 allocs
init crypto/dsa @6.5 ms, 0 ms clock, 16 bytes, 1 allocs
init crypto/x509 @6.5 ms, 0.016 ms clock, 4768 bytes, 15 allocs
init io/ioutil @6.7 ms, 0.002 ms clock, 16 bytes, 1 allocs
init vendor/golang.org/x/sys/cpu @6.7 ms, 0.009 ms clock, 1280 bytes, 1 allocs
init vendor/golang.org/x/crypto/chacha20poly1305 @6.8 ms, 0 ms clock, 16 bytes, 1 allocs
init vendor/golang.org/x/crypto/curve25519 @6.9 ms, 0 ms clock, 0 bytes, 0 allocs
init crypto/tls @7.0 ms, 0.007 ms clock, 1600 bytes, 11 allocs
init log @7.0 ms, 0 ms clock, 80 bytes, 1 allocs
init mime @7.1 ms, 0.008 ms clock, 1232 bytes, 4 allocs
init mime/multipart @7.2 ms, 0.001 ms clock, 192 bytes, 4 allocs
init compress/flate @7.3 ms, 0.012 ms clock, 4240 bytes, 7 allocs
init hash/crc32 @7.4 ms, 0.014 ms clock, 1024 bytes, 1 allocs
init compress/gzip @7.5 ms, 0 ms clock, 32 bytes, 2 allocs
init vendor/golang.org/x/text/transform @7.5 ms, 0 ms clock, 80 bytes, 5 allocs
init vendor/golang.org/x/text/unicode/bidi @7.6 ms, 0.005 ms clock, 272 bytes, 2 allocs
init vendor/golang.org/x/text/secure/bidirule @7.7 ms, 0.008 ms clock, 16 bytes, 1 allocs
init vendor/golang.org/x/text/unicode/norm @7.8 ms, 0.002 ms clock, 0 bytes, 0 allocs
init vendor/golang.org/x/net/idna @7.8 ms, 0 ms clock, 0 bytes, 0 allocs
init vendor/golang.org/x/net/http/httpguts @7.9 ms, 0.002 ms clock, 848 bytes, 3 allocs
init vendor/golang.org/x/net/http2/hpack @7.9 ms, 0.063 ms clock, 22440 bytes, 32 allocs
init net/http/internal @8.1 ms, 0.005 ms clock, 1808 bytes, 3 allocs
init vendor/golang.org/x/net/http/httpproxy @8.2 ms, 0 ms clock, 336 bytes, 2 allocs
init net/http @8.3 ms, 0.026 ms clock, 10280 bytes, 113 allocs

我們看到各個依賴包中的 init 函式執行的消耗情況都被輸出了出來,根據這些資訊,我們可以很容易判斷出 init 函式中可能存在的效能問題或瓶頸。

6. 連結器進一步優化

Go 1.15實現了 go linker 的第一階段優化後,Go 1.16 中繼續實施了對 linker 的第二階段優化。優化後的連結器要平均比 Go 1.15 的快 20%-25%,消耗的記憶體卻減少 5%-15%。

7. struct field 的 tag 中的多個 key 可以合併寫

如果某個結構體支援多種編碼格式的序列化和反序列化,比如:json、bson、xml,那麼之前版本需要按如下書寫該結構體的欄位 tag,冗長且重複:

type MyStruct struct {
  Field1 string `json:"field_1,omitempty" bson:"field_1,omitempty" xml:"field_1,omitempty" form:"field_1,omitempty" other:"value"`
}

Go 1.16 支援將多個 key 進行合併,上面的 tag 可以寫成如下形式:

type MyStruct struct {
  Field1 string `json bson xml form:"field_1,omitempty" other:"value"`
}

8. 其他改變

  • 新增 runtime/metrics 包,以替代 runtime.ReadMemStats 和 debug.ReadGCStats 輸出 runtime 的各種度量資料,這個包更通用穩定,效能也更好;
  • 新增 io/fs 包,用於提供只讀的操作 os 的檔案樹的高階介面;
  • 對 Unicode 標準的支援從 12.0.0 升級為 13.0.0。

附錄:安裝 go tip 版本的兩種方式

1) 從原始碼安裝

$git clone https//github.com/golang/go.git
$cd go/src
$./all.bash

2) 使用 gotip 工具安裝

$go get golang.org/dl/gotip
$gotip download

Go 技術專欄 “改善 Go 語⾔程式設計質量的 50 個有效實踐” 主要滿足廣大 gopher 關於 Go 語言進階的需求,圍繞如何寫出地道且高質量 Go 程式碼給出 50 條有效實踐建議,上線後收到一致好評!78 元簡直就是白菜價,簡直就是白 piao! 歡迎大家訂閱!

我的網課 “Kubernetes 實戰:高可用叢集搭建、配置、運維與應用” 在慕課網熱賣中,歡迎小夥伴們訂閱學習!

“Gopher 部落” 星球首開,福利自然是少不了的!2020 年年底之前,8.8 折加入星球。掃描下方圖片二維碼即享優惠!

Gopher Daily(Gopher 每日新聞) 歸檔倉庫 - https://github.com/bigwhite/gopherdaily

我的聯絡方式:

更多原創文章乾貨分享,請關注公眾號
  • Go 1.16 新功能特性不完全前瞻
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章