自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

萬字長文告訴你Go 1.20中值得關(guān)注的幾個變化

開發(fā) 前端
按照慣例,我們依舊首先來看看Go語法層面都有哪些變化,這可能也是多數(shù)Gopher們最為關(guān)注的變化點。

美國時間2023年2月1日,唯一尚未退休的Go語言之父Robert Griesemer[1]代表Go核心開發(fā)團隊在Go官博撰文正式發(fā)布了Go 1.20版本[2]。就像Russ Cox在2022 GopherCon大會[3]所說的那樣:**Go2永不會到來,Go 1.x.y將無限延續(xù)[4]**!

注:似乎新興編程語言都喜歡停留在1.x.y上無限延續(xù),譬如已經(jīng)演化到1.67版本的Rust[5]^_^。

在《Go,13周年》[6]之后,Go 1.20新特性在開發(fā)主干凍結(jié)(2022.11)之前,我曾寫過一篇《??Go 1.20新特性前瞻[??7]》,對照著Go 1.20 milestone[8]中內(nèi)容,把我認為的主要特性和大家簡單過了一遍,不過那時Go 1.20畢竟沒有正式發(fā)布,前瞻肯定不夠全面,某些具體的點與正式版本可能也有差異!現(xiàn)在Go 1.20版本正式發(fā)布了,其Release Notes[9]也補充完整了,在這一篇中,我再來系統(tǒng)說說Go 1.20版本中值得關(guān)注的那些變化。對于在前瞻一文[10]中詳細介紹過的特性,這里不會再重復講解了,大家參考前瞻一文中的內(nèi)容即可。而對于其他一些特性,或是前瞻一文中著墨不多的特性,這里會挑重點展開說說。

按照慣例,我們依舊首先來看看Go語法層面都有哪些變化,這可能也是多數(shù)Gopher們最為關(guān)注的變化點。

一. 語法變化

Go秉持“大道至簡”的理念,對Go語法特性向來是“不與時俱進”的。自從Go 1.18大刀闊斧的加入了泛型特性[11]后,Go語法特性就又恢復到了之前的“新三年舊三年,縫縫補補又三年”的節(jié)奏。Go 1.20亦是如此??!Release Notes說Go 1.20版本在語言方面包含了四點變化,但看了變化的內(nèi)容后,我覺得真正的變化只有一個,其他的都是修修補補。

1. 切片到數(shù)組的轉(zhuǎn)換

唯一算是真語法變化的特性是支持切片類型到數(shù)組類型(或數(shù)組類型的指針)的類型轉(zhuǎn)換,這個特性在前瞻一文[12]中系統(tǒng)講過,這里就不贅述了,放個例子大家直觀認知一下就可以了:

// https://github.com/bigwhite/experiments/blob/master/go1.20-examples/lang/slice2arr.go

func slice2arrOK() {
var sl = []int{1, 2, 3, 4, 5, 6, 7}
var arr = [7]int(sl)
var parr = (*[7]int)(sl)
fmt.Println(sl) // [1 2 3 4 5 6 7]
fmt.Println(arr) // [1 2 3 4 5 6 7]
sl[0] = 11
fmt.Println(arr) // [1 2 3 4 5 6 7]
fmt.Println(parr) // &[11 2 3 4 5 6 7]
}

func slice2arrPanic() {
var sl = []int{1, 2, 3, 4, 5, 6, 7}
fmt.Println(sl)
var arr = [8]int(sl) // panic: runtime error: cannot convert slice with length 7 to array or pointer to array with leng th 8
fmt.Println(arr) // &[11 2 3 4 5 6 7]

}

func main() {
slice2arrOK()
slice2arrPanic()
}

有兩點注意一下就好:

  • 切片轉(zhuǎn)換為數(shù)組類型的指針,那么該指針將指向切片的底層數(shù)組,就如同上面例子中slice2arrOK的parr變量那樣;
  • 轉(zhuǎn)換的數(shù)組類型的長度不能大于原切片的長度(注意是長度而不是切片的容量哦),否則在運行時會拋出panic。

2. 其他的修修補補

  • comparable“放寬”了對泛型實參的限制

下面代碼在Go 1.20版本之前,比如Go 1.19版本中會無法通過編譯:

// https://github.com/bigwhite/experiments/blob/master/go1.20-examples/lang/comparable.go

func doSth[T comparable](t T) {
}

func main() {
n := 2
var i interface{} = n // 編譯錯誤:interface{} does not implement comparable
doSth(i)
}

之前,comparable約束下的泛型形參需要支持嚴格可比較(strictly comparable)的類型作為泛型實參,哪些是嚴格可比較的類型呢?Go 1.20的語法規(guī)范做出了進一步澄清:如果一個類型是可比較的,且不是接口類型或由接口類型組成的類型,那么這個類型就是嚴格可比較的類型,包括:

- 布爾型、數(shù)值類型、字符串類型、指針類型和channel是嚴格可比較的。
- 如果結(jié)構(gòu)體類型的所有字段的類型都是嚴格可比較的,那么該結(jié)構(gòu)體類型就是嚴格可比較的。
- 如果數(shù)組元素的類型是嚴格可比較的,那么該數(shù)組類型就是嚴格可比較的。
- 如果類型形參的類型集合中的所有類型都是嚴格可比較的,那么該類型形參就是嚴格可比較的。

我們看到:例外的就是接口類型了。接口類型不是“嚴格可比較的(strictly comparable)”,但未作為類型形參的接口類型是可比較的(comparable),如果兩個接口類型的動態(tài)類型相同且值相等,那么這兩個接口類型就相等,或兩個接口類型的值均為nil,它們也相等,否則不等。

Go 1.19版本及之前,作為非嚴格比較類型的接口類型是不能作為comparable約束的類型形參的類型實參的,就像上面comparable.go中示例代碼那樣,但Go 1.20版本開始,這一要求被防控,接口類型被允許作為類型實參賦值給comparable約束的類型形參了!不過這么做之前,你也要明確一點,如果像下面這樣兩個接口類型底層類型相同且是不可比較的類型(比如切片),那么代碼將在運行時拋panic:

// https://github.com/bigwhite/experiments/blob/master/go1.20-examples/lang/comparable1.go

func doSth[T comparable](t1, t2 T) {
if t1 != t2 {
println("unequal")
return
}
println("equal")
}

func main() {
n1 := []byte{2}
n2 := []byte{3}
var i interface{} = n1
var j interface{} = n2
doSth(i, j) // panic: runtime error: comparing uncomparable type []uint8
}

Go 1.20語言規(guī)范借此機會還進一步澄清了結(jié)構(gòu)體和數(shù)組兩種類型比較實現(xiàn)的規(guī)范:對于結(jié)構(gòu)體類型,Go會按照結(jié)構(gòu)體字段的聲明順序,逐一字段進行比較,直到遇到第一個不相等的字段為止。如果沒有不相等字段,則兩個結(jié)構(gòu)體字段相等;對于數(shù)組類型,Go會按數(shù)組元素的順序,逐一元素進行比較,直到遇到第一個不相等的元素為止。如果沒有不相等的元素,則兩個數(shù)組相等。

  • unsafe包繼續(xù)添加“語法糖”

繼Go 1.17版本[13]在unsafe包增加Slice函數(shù)后,Go 1.20版本又增加三個語法糖函數(shù):SliceData、String和StringData:

// $GOROOT/src/unsafe/unsafe.go
func SliceData(slice []ArbitraryType) *ArbitraryType
func String(ptr *byte, len IntegerType) string
func StringData(str string) *byte

值得注意的是由于string的不可更改性,String函數(shù)的參數(shù)ptr指向的內(nèi)容以及StringData返回的指針指向的內(nèi)容在String調(diào)用和StringData調(diào)用后不允許修改,但實際情況是怎么樣的呢?

// https://github.com/bigwhite/experiments/blob/master/go1.20-examples/lang/unsafe.go

func main() {
var arr = [6]byte{'h', 'e', 'l', 'l', 'o', '!'}
s := unsafe.String(&arr[0], 6)
fmt.Println(s) // hello!
arr[0] = 'j'
fmt.Println(s) // jello!

s1 := "golang"
fmt.Println(s1) // golang
b := unsafe.StringData(s1)
*b = 'h' // fatal error: fault, unexpected fault address 0x10a67e5
fmt.Println(s1)
}

我們看到:unsafe.String函數(shù)調(diào)用后,如果我們修改了傳入的指針指向的內(nèi)容,那么該改動會影響到后續(xù)返回的string內(nèi)容!但StringData返回的指針所指向的內(nèi)容一旦被修改,就會導致運行時的段錯誤,從而程序崩潰!

二. 工具鏈

1. Go安裝包“瘦身”

這些年,Go發(fā)布版的安裝包“體格”是越來越壯了,動輒100多MB的壓縮包,以go.dev/dl頁面上的go1.xy.linux-amd64.tar.gz為例,我們看看從Go 1.15版本到Go 1.19版本的“體格”變化趨勢:

Go 1.15 - 116MB
Go 1.16 - 123MB
Go 1.17 - 129MB
Go 1.18 - 135MB
Go 1.19 - 142MB

如果按此趨勢,Go 1.20勢必要上到150MB以上。但Go團隊找到了“瘦身”方法,那就是:從Go 1.20開始發(fā)行版的安裝包不再為GOROOT中的軟件包提供預編譯的.a文件了[14],這樣我們得到的瘦身后的Go 1.20版本的size為95MB!相較于Go 1.19,Go 1.20的安裝包“瘦”了三分之一。安裝包解壓后這種體現(xiàn)更為明顯:

?  /Users/tonybai/.bin/go1.19 git:(master) ? $du -sh
495M .
? /Users/tonybai/.bin/go1.20 git:(master) ? $du -sh
265M .

我們看到:Go 1.20占用的磁盤空間僅為Go 1.19版本的一半多一點而已。并且,Go 1.20版本中,GOROOT下的源碼將像其他用戶包那樣在構(gòu)建后被緩存到本機cache中。此外,go install也不會為GOROOT下的軟件包安裝.a文件。

2. 編譯器

1) PGO(profile-guided optimization)

Go 1.20編譯器的一個最大的變更點是引入了PGO優(yōu)化技術(shù)預覽版,這個在前瞻一文中也有對PGO技術(shù)的簡單介紹[15]。說白了點,PGO技術(shù)就是在原有compiler優(yōu)化技術(shù)的基礎(chǔ)上,針對程序在生產(chǎn)環(huán)境運行中的熱點關(guān)鍵路徑再進行一輪優(yōu)化,并且針對熱點代碼執(zhí)行路徑,編譯器會放開一些限制,比如Go決定是否對函數(shù)進行內(nèi)聯(lián)優(yōu)化的復雜度上限默認值是80[16],但對于PGO指示的關(guān)鍵熱點路徑,即便函數(shù)復雜性超過80很多,也可能會被inline優(yōu)化掉。

之前持續(xù)性能剖析工具開發(fā)商Polar Signals曾發(fā)布一篇文章《Exploring Go's Profile-Guided Optimizations》[17],專門探討了PGO技術(shù)可能帶來的優(yōu)化效果,文章中借助了Go項目中自帶的測試示例,這里也基于這個示例帶大家重現(xiàn)一下。

我們使用的例子在Go 1.20源碼/安裝包的$GOROOT/src/cmd/compile/internal/test/testdata/pgo/inline路徑下:

$ls -l
total 3156
-rw-r--r-- 1 tonybai tonybai 1698 Jan 31 05:46 inline_hot.go
-rw-r--r-- 1 tonybai tonybai 843 Jan 31 05:46 inline_hot_test.go

我們首先執(zhí)行一下inline目錄下的測試,并生成用于測試的可執(zhí)行文件以及對應(yīng)的cpu profile文件供后續(xù)PGO優(yōu)化使用:

$go test -o inline_hot.test -bench=. -cpuprofile inline_hot.pprof
goos: linux
goarch: amd64
pkg: cmd/compile/internal/test/testdata/pgo/inline
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkA-8 1348 870005 ns/op
PASS
ok cmd/compile/internal/test/testdata/pgo/inline 1.413s

接下來,我們對比一下不使用PGO和使用PGO優(yōu)化,Go編譯器在內(nèi)聯(lián)優(yōu)化上的區(qū)別:

$diff <(go test -run=none -tags='' -timeout=9m0s -gcflags="-m -m" 2>&1 | grep "can inline") <(go test -run=none -tags='' -timeout=9m0s -gcflags="-m -m -pgoprofile inline_hot.pprof" 2>&1 | grep "can inline")
4a5,6
> ./inline_hot.go:53:6: can inline (*BS).NS with cost 106 as: method(*BS) func(uint) (uint, bool) { x := int(i >> lWSize); if x >= len(b.s) { return 0, false }; w := b.s[x]; w = w >> (i & (wSize - 1)); if w != 0 { return i + T(w), true }; x = x + 1; for loop; return 0, false }
> ./inline_hot.go:74:6: can inline A with cost 312 as: func() { s := N(100000); for loop; for loop }

上面diff命令中為Go test命令傳入-run=none -tags="" -gcflags="-m -m"是為了僅編譯源文件,而不執(zhí)行任何測試。

我們看到,相較于未使用PGO優(yōu)化的結(jié)果,PGO優(yōu)化后的結(jié)果多了兩個inline函數(shù),這兩個可以被inline的函數(shù),一個的復雜度開銷為106,一個是312,都超出了默認的80,但仍然可以被inline。

我們來看看PGO的實際優(yōu)化效果,我們分為在無PGO優(yōu)化與有PGO優(yōu)化下執(zhí)行100次benchmark,再用benchstat工具對比兩次的結(jié)果:

$go test -o inline_hot.test -bench=. -cpuprofile inline_hot.pprof -count=100 > without_pgo.txt
$go test -o inline_hot.test -bench=. -gcflags="-pgoprofile inline_hot.pprof" -count=100 > with_pgo.txt

$benchstat without_pgo.txt with_pgo.txt
goos: linux
goarch: amd64
pkg: cmd/compile/internal/test/testdata/pgo/inline
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
│ without_pgo.txt │ with_pgo.txt
│ sec/op │ sec/op vs base │
A-8 874.7μ ± 0% 872.6μ ± 0% -0.24% (p=0.024 n=100)

注:benchstat的安裝方法:$go install golang.org/x/perf/cmd/benchstat@latest

我們看到,在我的機器上(ubuntu 20.04 linux kerenel 5.4.0-132),PGO針對這個測試的優(yōu)化效果并不明顯(僅僅有0.24%的提升),Polar Signals原文中的提升幅度也不大,僅為1.05%。

Go官方Release Notes中提到benchmark提升效果為3%~4%,同時官方也提到了,這個僅僅是PGO初始技術(shù)預覽版,后續(xù)會加強對PGO優(yōu)化的投入,直至對多數(shù)程序產(chǎn)生較為明顯的優(yōu)化效果。個人覺得目前PGO尚處于早期,不建議在生產(chǎn)中使用。

Go官方也增加針對PGO的ref頁面[18],大家重點看看其中的FAQ,你會有更多收獲!

2) 構(gòu)建速度

Go 1.18泛型落地后,Go編譯器的編譯速度出現(xiàn)了回退(幅度15%),Go 1.19編譯速度也沒有提升。雖然編譯速度回退后依然可以“秒殺”競爭對手,但對于以編譯速度快著稱的Go來說,這個問題必須修復。Go 1.20做到了這一點,讓Go編譯器的編譯速度重新回歸到了Go 1.17的水準!相對Go 1.19提升10%左右。

我使用github.com/reviewdog/reviewdog這個庫實測了一下,分別使用go 1.17.1、go 1.18.6、go 1.19.1和Go 1.20對這個module進行g(shù)o build -a構(gòu)建(之前將依賴包都下載本地,排除掉go get環(huán)節(jié)的影響),結(jié)果如下:

go 1.20
$time go build -a github.com/reviewdog/reviewdog/cmd/reviewdog
go build -a github.com/reviewdog/reviewdog/cmd/reviewdog 48.01s user 7.96s system 536% cpu 10.433 total

go 1.19.1
$time go build -a github.com/reviewdog/reviewdog/cmd/reviewdog
go build -a github.com/reviewdog/reviewdog/cmd/reviewdog 54.40s user 10.20s system 506% cpu 12.757 total

go 1.18.6
$time go build -a github.com/reviewdog/reviewdog/cmd/reviewdog
go build -a github.com/reviewdog/reviewdog/cmd/reviewdog 53.78s user 9.85s system 545% cpu 11.654 total

go 1.17.1
$time go build -a github.com/reviewdog/reviewdog/cmd/reviewdog
go build -a github.com/reviewdog/reviewdog/cmd/reviewdog 50.30s user 9.76s system 580% cpu 10.338 total

雖然不能十分精確,但總體上反映出各個版本的編譯速度水準以及Go 1.20相對于Go 1.18和Go 1.19版本的提升。我們看到Go 1.20與Go 1.17版本在一個水平線上,甚至要超過Go 1.17(但可能僅限于我這個個例)。

3) 允許在泛型函數(shù)/方法中進行類型聲明

Go 1.20版本之前下面代碼是無法通過Go編譯器的編譯的:

// https://github.com/bigwhite/experiments/blob/master/go1.20-examples/tools/compiler/local_type_decl.go
package main

func F[T1 any]( "T1 any") {
type x struct{} // 編譯錯誤:type declarations inside generic functions are not currently supported
type y = x // 編譯錯誤:type declarations inside generic functions are not currently supported
}

func main() {
F[int]( "int")
}

Go 1.20改進了語言前端的實現(xiàn)[19],通過unified IR實現(xiàn)了對在泛型函數(shù)/方法中進行類型聲明(包括定義type alias)的支持。

同時,Go 1.20在spec[20]中還明確了哪些使用了遞歸方式聲明的類型形參列表是不合法的[21]:

type T1[P T1[P]]// 不合法: 形參列表中作為約束的T1引用了自己
type T2[P interface{ T2[int] }]// 不合法: 形參列表中作為約束的T2引用了自己
type T3[P interface{ m(T3[int])}]// 不合法: 形參列表中作為約束的T3引用了自己

type T4[P T5[P]]// 不合法: 形參列表中,T4引用了T5 并且
type T5[P T4[P]]// T5引用了T4

type T6[P int] struct{ f *T6[P] } // 正確: 雖然引用了T6,但這個引用發(fā)生在結(jié)構(gòu)體定義中而不是形參列表中

4) 構(gòu)建自舉源碼的Go編譯器的版本選擇

Go從Go 1.5版本開始實現(xiàn)自舉,即使用Go實現(xiàn)Go,那么自舉后的Go項目是誰來編譯的呢?最初對應(yīng)編譯Go 1.5版本的Go編譯器版本為Go 1.4。

以前從源碼構(gòu)建Go發(fā)行版,當未設(shè)置GOROOT_BOOTSTRAP時,編譯腳本會默認使用Go 1.4,但如果有更高版本的Go編譯器存在,會使用更高版本的編譯器。

Go 1.18和Go 1.19會首先尋找是否有g(shù)o 1.17版本,如果沒有再使用go 1.4。

Go 1.20會尋找當前Go 1.17的最后一個版本Go 1.17.13,如果沒有,則使用Go 1.4。

將來,Go核心團隊計劃一年升級一次構(gòu)建自舉源碼的Go編譯器的版本,例如:Go 1.22版本將使用Go 1.20版本的編譯器。

5) cgo

Go命令現(xiàn)在在沒有C工具鏈的系統(tǒng)上會默認禁用了cgo。更具體來說,當CGO_ENABLED環(huán)境變量未設(shè)置,CC環(huán)境變量未設(shè)置以及PATH環(huán)境變量中沒有找到默認的C編譯器(通常是clang或gcc)時,CGO_ENABLED會被默認設(shè)置為0。

3. 其他工具

1) 支持采集應(yīng)用執(zhí)行的代碼蓋率

在前瞻一文中,我提到過Go 1.20將對代碼覆蓋率的支持擴展到了應(yīng)用整體層面,而不再僅僅是unit test。這里使用一個例子來看一下,究竟如何采集應(yīng)用代碼的執(zhí)行覆蓋率。我們以gitlab.com/esr/loccount這個代碼統(tǒng)計工具為例,先修改一下Makefile,在go build后面加上-cover選項,然后編譯loccount,并對其自身進行代碼統(tǒng)計:

// /home/tonybai/go/src/gitlab.com/loccount
$make
$mkdir mycovdata
$GOCOVERDIR=./mycovdata loccount .
all SLOC=4279 (100.00%) LLOC=1213 in 110 files
Go SLOC=1724 (40.29%) LLOC=835 in 3 files
asciidoc SLOC=752 (17.57%) LLOC=0 in 5 files
C SLOC=278 (6.50%) LLOC=8 in 2 files
Python SLOC=156 (3.65%) LLOC=0 in 2 files
... ...

上面執(zhí)行l(wèi)occount之前,我們建立了一個mycovdata目錄,并設(shè)置GOCOVERDIR的值為mycovdata目錄的路徑。在這樣的上下文下,執(zhí)行l(wèi)occount后,mycovdata目錄下會生成一些覆蓋率統(tǒng)計數(shù)據(jù)文件:

$ls mycovdata 
covcounters.4ec45ce64f965e77563ecf011e110d4f.926594.1675678144659536943 covmeta.4ec45ce64f965e77563ecf011e110d4f

怎么查看loccount的執(zhí)行覆蓋率呢?我們使用go tool covdata來查看:

$go tool covdata percent -i=mycovdata
loccount coverage: 69.6% of statements

當然, covdata子命令還支持其他一些功能,大家可以自行查看manual挖掘。

2) vet

Go 1.20版本中,go工具鏈的vet子命令增加了兩個十分實用的檢測:

  • 對loopclosure這一檢測策略進行了增強

具體可參見https://github.com/golang/tools/tree/master/go/analysis/passes/loopclosure代碼

  • 增加對2006-02-01的時間格式的檢查

注意我們使用time.Format或Parse時,最常使用的是2006-01-02這樣的格式,即ISO 8601標準的時間格式,但一些代碼中總是出現(xiàn)2006-02-01,十分容易導致錯誤。這個版本中,go vet將會對此種情況進行檢查。

三. 運行時與標準庫

1. 運行時(runtime)

Go 1.20運行時的調(diào)整并不大,僅對GC的內(nèi)部數(shù)據(jù)結(jié)構(gòu)進行了微調(diào),這個調(diào)整可以獲得最多2%的內(nèi)存開銷下降以及cpu性能提升。

2. 標準庫

標準庫肯定是變化最多的那部分。前瞻一文中對下面變化也做了詳細介紹,這里不贅述了,大家可以翻看那篇文章細讀:

  • 支持wrap multiple errors
  • time包新增DateTime、DateOnly和TimeOnly三個layout格式常量
  • 新增arena包 ... ...

標準庫變化很多,這里不能一一羅列,再補充一些我認為重要的,其他的變化大家可以到Go 1.20 Release Notes[22]去看:

1) arena包

前瞻一文已經(jīng)對arena包做了簡要描述,對于arena包的使用以及最佳適用場合的探索還在進行中。著名持續(xù)性能剖析工具pyroscope[23]的官方博客文章《Go 1.20 arenas實踐:arena vs. 傳統(tǒng)內(nèi)存管理》[24]對于arena實驗特性的使用給出了幾點好的建議,比如:

  • 只在關(guān)鍵的代碼路徑中使用arena,不要到處使用它們
  • 在使用arena之前和之后對你的代碼進行profiling,以確保你在能提供最大好處的地方添加arena。
  • 密切關(guān)注arena上創(chuàng)建的對象的生命周期。確保你不會把它們泄露給你程序中的其他組件,因為那里的對象可能會超過arena的壽命。
  • 使用defer a.Free()來確保你不會忘記釋放內(nèi)存。
  • 如果你想在arena被釋放后使用對象,使用arena.Clone()將其克隆回heap中。

pyroscope的開發(fā)人員認為arena是一個強大的工具,也支持標準庫中保留arena這個特性,但也建議將arena和reflect、unsafe、cgo等一樣納入“不推薦”使用的包行列。這點我也是贊同的。我也在考慮如何基于arena改進我們產(chǎn)品的協(xié)議解析器的性能,有成果后,我也會將實踐過程分享出來的。

2) 新增crypto/ecdh包

密碼學包(crypto)的主要maintainer Filippo Valsorda[25]從google離職后,成為了一名專職開源項目維護者[26]。這似乎讓其更有精力和動力對crypto包進行更好的規(guī)劃、設(shè)計和實現(xiàn)了。crypto/ecdh包就是在他的提議下加入到Go標準庫中的[27]。

相對于標準庫之前存在的crypto/elliptic等包,crypto/ecdh包的API更為高級,Go官方推薦使用ecdh的高級API,這樣大家以后可以不必再與低級的密碼學函數(shù)斗爭了。

3) HTTP ResponseController

以前HTTP handler的超時都是http服務(wù)器全局指定一個的:包括ReadTimeout和WriteTimeout。但有些時候,如果能在某個請求范圍內(nèi)支持這些超時(以及可能的其他選項)將非常有用。Damien Neil就創(chuàng)建了這個增加ResponseController的提案[28],下面是一個在HandlerFunc中使用ResponseController的例子:

http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
ctl := http.NewResponseController(w, r)
ctl.SetWriteDeadline(time.Now().Add(1 * time.Minute)) // 僅為這個請求設(shè)置deadline
fmt.Fprintln(w, "Hello, world.") // 這個寫入的timeout為1-minute
})

4) context包增加WithCancelCause函數(shù)

context包新增了一個WithCancelCause函數(shù),與WithCancel不同,通過WithCancelCause返回的Context,我們可以得到cancel的原因,比如下面示例:

// https://github.com/bigwhite/experiments/blob/master/go1.20-examples/library/context.go

func main() {
myError := fmt.Errorf("%s", "myError")
ctx, cancel := context.WithCancelCause(context.Background())
cancel(myError)
fmt.Println(ctx.Err()) // context.Canceled
fmt.Println(context.Cause(ctx)) // myError
}

我們看到通過context.Cause可以得到Context在cancel時傳入的錯誤原因。

四. 移植性

Go對新cpu體系結(jié)構(gòu)和OS的支持向來是走在前面的。Go 1.20還新增了對freebsd在risc-v上的實驗性支持,其環(huán)境變量為GOOS=freebsd, GOARCH=riscv64。但Go 1.20也將成為對下面平臺提供支持的最后一個Go版本:

  • Windows 7, 8, Server 2008和Server 2012
  • MacOS 10.13 High Sierra和10.14 (我的安裝了10.14的mac os又要在go 1.21不被支持了^_^)

近期Go團隊又有了新提案:支持WASI(GOOS=wasi GOARCH=wasm)[29],WASI是啥,它是WebAssembly一套與引擎無關(guān)(engine-indepent)的、面向非Web系統(tǒng)的WASM API標準,是WebAssembly脫離瀏覽器的必經(jīng)之路!一旦生成滿足WASI的WASM程序,該程序就可以在任何支持WASI或兼容的runtime上運行。不出意外,該提案將在Go 1.21或Go 1.22版本落地。

本文中的示例代碼可以在這里[30]下載。

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

  • 微博(暫不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite

參考資料

[1] Robert Griesemer: https://github.com/griesemer

[2] Go官博撰文正式發(fā)布了Go 1.20版本: https://go.dev/blog/go1.20

[3] Russ Cox在2022 GopherCon大會: https://www.youtube.com/watch?v=v24wrd3RwGo

[4] Go2永不會到來,Go 1.x.y將無限延續(xù): https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language

[5] 演化到1.67版本的Rust: https://www.rust-lang.org

[6] 《Go,13周年》: https://tonybai.com/2022/11/11/go-opensource-13-years/

[7] Go 1.20新特性前瞻: https://tonybai.com/2022/11/17/go-1-20-foresight

[8] Go 1.20 milestone: https://github.com/golang/go/milestone/250

[9] Release Notes: https://go.dev/blog/go1.20

[10] 前瞻一文: https://tonybai.com/2022/11/17/go-1-20-foresight

[11] Go 1.18大刀闊斧的加入了泛型特性: https://tonybai.com/2022/04/20/some-changes-in-go-1-18

[12] 前瞻一文: https://tonybai.com/2022/11/17/go-1-20-foresight

[13] Go 1.17版本: https://tonybai.com/2021/08/17/some-changes-in-go-1-17

[14] 從Go 1.20開始發(fā)行版的安裝包不再為GOROOT中的軟件包提供預編譯的.a文件了: https://github.com/golang/go/issues/47257

[15] 對PGO技術(shù)的簡單介紹: https://tonybai.com/2022/11/17/go-1-20-foresight

[16] Go決定是否對函數(shù)進行內(nèi)聯(lián)優(yōu)化的復雜度上限默認值是80: https://tonybai.com/2022/10/17/understand-go-inlining-optimisations-by-example

[17] 《Exploring Go's Profile-Guided Optimizations》: https://www.polarsignals.com/blog/posts/2022/09/exploring-go-profile-guided-optimizations/

[18] PGO的ref頁面: https://go.dev/doc/pgo

[19] Go 1.20改進了語言前端的實現(xiàn): https://github.com/golang/go/issues/47631

[20] spec: https://go.dev/ref/spec#Type_parameter_declarations

[21] 哪些使用了遞歸方式聲明的類型形參列表是不合法的: https://github.com/golang/go/issues/40882

[22] Go 1.20 Release Notes: https://go.dev/doc/go1.20

[23] pyroscope: https://pyroscope.io/

[24] 《Go 1.20 arenas實踐:arena vs. 傳統(tǒng)內(nèi)存管理》: https://pyroscope.io/blog/go-1-20-memory-arenas/

[25] Filippo Valsorda: https://filippo.io/

[26] 成為了一名專職開源項目維護者: https://words.filippo.io/full-time-maintainer/

[27] crypto/ecdh包就是在他的提議下加入到Go標準庫中的: https://github.com/golang/go/issues/52221

[28] 增加ResponseController的提案: https://github.com/golang/go/issues/54136

[29] 支持WASI(GOOS=wasi GOARCH=wasm): https://github.com/golang/go/issues/58141

[30] 這里: https://github.com/bigwhite/experiments/blob/master/go1.20-examples

[31] “Gopher部落”知識星球: https://wx.zsxq.com/dweb2/index/group/51284458844544

本文轉(zhuǎn)載自微信公眾號「 白明的贊賞賬戶」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系白明的贊賞賬戶公眾號。

責任編輯:武曉燕 來源: TonyBai
相關(guān)推薦

2024-02-19 08:07:31

Go版本語言

2021-10-18 11:58:56

負載均衡虛擬機

2022-09-06 08:02:40

死鎖順序鎖輪詢鎖

2021-01-19 05:49:44

DNS協(xié)議

2022-09-14 09:01:55

shell可視化

2024-03-07 18:11:39

Golang采集鏈接

2020-07-15 08:57:40

HTTPSTCP協(xié)議

2020-11-16 10:47:14

FreeRTOS應(yīng)用嵌入式

2023-06-12 08:49:12

RocketMQ消費邏輯

2020-07-09 07:54:35

ThreadPoolE線程池

2022-10-10 08:35:17

kafka工作機制消息發(fā)送

2022-07-19 16:03:14

KubernetesLinux

2020-06-22 16:55:49

前端異常處理錯誤

2024-05-10 12:59:58

PyTorch人工智能

2022-09-08 10:14:29

人臉識別算法

2024-01-11 09:53:31

面試C++

2024-01-05 08:30:26

自動駕駛算法

2022-07-15 16:31:49

Postman測試

2021-08-26 05:02:50

分布式設(shè)計

2022-04-25 10:56:33

前端優(yōu)化性能
點贊
收藏

51CTO技術(shù)棧公眾號