Go1.20 那些事:PGO、編譯速度、錯誤處理等新特性,你知道多少?
最近Go1.20 在2 月初已經正式發布,來的挺早的,以往都是拖到月底的,我翻了好幾篇,發現最後還是做了不少功能取捨,被迫放了某些新特性(例如:arena 等)的鴿子!
懷疑 Go 團隊 2 月是有什麼事要幹,或是打算休假?又或是擔心裁員影響工作交接?
今天快速溫習與我們關聯性多些的新特性,看看升不升 1.20。
編譯速度提高
之前 Go1.18 正式發布了泛型,有歡喜也有憂。這雖然支援了泛型,但在 Go1.18 起編譯速度相對 Go1.17 變慢了,會慢大概 15-18%,降速明顯。

泛型特性,把 Go 引以為傲的建構速度都變慢了。怕不是以後建構也可以沖咖啡喝了?
原本說在 Go1.19 修,鴿了。終於,目前版本已經修復了。
如下測試報告:
│ 117.results │ 118.results │ 119.results │ tip.results │ │ sec/op │ sec/op vs base │ sec/op vs base │ sec/op vs base │ GoBuildKubelet 52.58 ± 0% 56.54 ± 1% +7.54% (p=0.000 n=10) 55.47 ± 1% +5.50% (p=0.000 n=10) 51.41 ± 1% -2.22% (p=0.000 n=10) GoBuildIstioctl 47.78 ± 1% 51.44 ± 0% +7.65% (p=0.000 n=10) 50.89 ± 5% +6.50% (p=0.000 n=10) 46.05 ± 1% -3.62% (p=0.000 n=10) GoBuildFrontend 19.03 ± 1% 20.55 ± 1% +7.99% (p=0.000 n=10) 20.04 ± 0% +5.33% (p=0.000 n=10) 18.22 ± 1% -4.27% (p=0.000 n=10) geomean 36.29 39.10 +7.72% 38.39 +5.77% 35.07 -3.37%
最新的 Go1.20 基準測試中,目前版本和 Go1.17 的建置速度保持一致。
另外還優化了編譯器和垃圾收集器,減少了記憶體開銷,將整體 CPU 效能提高了 2%。
Go1.21 將結束MacOS、Windows 部分版本支援
Go1.20 的更新公告中也宣布了一個重大的更新結束通知,涉及macOS 和windows作業系統.

分別如下:
Go1.20 是支援macOS 10.13 High Sierra 或10.14 Mojave 上運行的最後一個版本。 Go 1.21 將需要 macOS 10.15 Catalina 或更高版本。
Go1.20 是支援 Windows 7、8、Server 2008 和 Server 2012 的任何版本上執行的最後一個版本。 Go 1.21 將至少需要 Windows 10 或 Server 2016。
好傢伙,看來我需要更新我的作業系統版本了,不然下個版本 Go 都不歡迎我 coding 了。

有需要的同学在下个版本前尽早做好升级。
Go 发行版瘦身
新版本起,Go 的 $GOROOT/pkg
目录将不再存储标准库的预编译包存档,Go 发行版的将迎来一轮瘦身。
大小对比如下。
Go1.20:

Go1.19:

约比老版本缩减了 1/3,还是比较明显的。
PGO 引入
在 Go1.20 起,Go 引入了 Profile-guided optimization (PGO),翻译过来是使用配置文件引导的优化,当前为预览版本。
PGO 是一门编译器优化技术,能够在不改业务代码的情况下,给你的应用程序带来一定的性能提升。在 Go PGO 中将会依托 runtime/pprof 所生成的 profile 来完成。

结果上可以使得 Go tool(工具链)能根据运行时信息执行特定于应用程序和工作负载的优化。说明了就是想提高性能,不需要改业务代码。
具体可以详见:《PGO 是啥,咋就让 Go 更快更猛了?》
支持封装多个错误
在原有 Go1.13 的 errors API 上进行新增和修改,核心是支持一个错误可以封装多个错误的特性。
新特性例子:
func main() { err1 := errors.New("err1") err2 := errors.New("err2") err := errors.Join(err1, err2) fmt.Println(err) if errors.Is(err, err1) { fmt.Println("err is err1") } if errors.Is(err, err2) { fmt.Println("err is err2") } }
输出结果:
err1 err2 err is err1 err is err2
具体可以详见:《Go1.20 继续小修小补 errors 库。。。》
新增 StringData, String, SliceData
Go 团队通过分析、搜索发现 reflect.SliceHeader 和 reflect.StringHeader:
type StringHeader struct { Data uintptr Len int }
在业内经常被滥用,使用不方便,很容易出现隐性问题。例如:Data 字段类型是 uintptr 不是 unsafe.Pointer。设什么都可以,灵活度过于高,非常容易搞出问题。
在 Go1.20 起,在 unsafe 标准库新增了 3 个函数来替代前面这两个类型的使用。希望能够进一步标准化,并提供额外的类型安全。

如下函数签名:
func String(ptr *byte, len IntegerType) string
:根据数据指针和字符长度构造一个新的 string。func StringData(str string) *byte
:返回指向该 string 的字节数组的数据指针。func SliceData(slice []ArbitraryType) *ArbitraryType
:返回该 slice 的数据指针。
新版本的用法变成:
func StringToBytes(s string) []byte { return unsafe.Slice(unsafe.StringData(s), len(s)) } func BytesToString(b []byte) string { return unsafe.String(&b[0], len(b)) }
以往常用的 reflect.SliceHeader
和 reflect.StringHeader
将会被标注为被废弃。
具体可以详见:《别乱用了,用新的。Go SliceHeader 和 StringHeader 将会被废弃!》
优化时间比较和格式记忆
2006-01-02 15:04:05
有很多 Go 同学反馈老要记 2006-01-02 15:04:05,发现这个日期时间点,使用的次数非常高频:
排名 | 頻率 | 格式 |
---|---|---|
1 | 75616 | time.RFC3339 |
#2 | 23954 | time.RFC3339Nano |
3 | 13312 | "2006-01-02 15:04:05" |
#4 | 12332 | "2006-01-02" |
#5 | 11940 | time.RFC1123 |
使用频率的数据有理有据。
Go1.20 加了以下常量,便于直接引用:
DateTime = "2006-01-02 15:04:05" DateOnly = "2006-01-02" TimeOnly = "15:04:05"
Time.Compare
再者就是新增了时间比较的方法。
在现在的标准库中,有 3 个方法来比较 time.Time 对象,分别是:Before()、Equal() 和 After(),作用上类似 <、== 和 >。但缺少 <= 和 >= 的等价物。
Go1.20 将会支持 Time.Compare,以此来达到类似的效果。作用是将 Time 对象 t 和 u 两者进行比较。
func (t Time) Compare(u Time) int
该方法返回如下几种结果:
如果 t 在 u 之前,则返回 -1。 如果 t 在 u 之后,则返回 +1。 如果它们相同,则返回 0。
具体可以详见:《Go1.20 中两个关于 Time 的更新,终于不用背 2006-01-02 15:04:05 了!》
禁用匿名接口循环导入
以前可以做匿名接口循环导入的骚操作。如下代码:
type I interface { m() interface { I } }
这段代码,声明了接口类型 I,然后又包含了 m(),又包含接口 I。这会是一个 “永动机”,永远都不会停止。在开源的 GitHub 中,也真实存在着。
Go1.20 起,编译器将会默认拒绝匿名接口循环导入。如果没有用户反馈受到了重大的影响或问题,将会计划在 Go1.22 中正式的禁用和移除该项功能的支持。
具体可以详见:《Go1.20 将禁止匿名接口循环导入!》
没有 C工具链默认禁用 CGO
Go1.20 将会在没有 C 工具链的系统上默认禁用 CGO。这理论上是一个不兼容性设置,如果大家有需要,可以提前设置好 CGO_ENABLED 环境变量,以避免导致部分应用程序出问题。
支持切片到数组的转换
Go1.20 起支持将切片转换成数组。
如下代码:
func main() { v := []string{"煎", "鱼", "进", "脑", "子", "了"} s := [6]string(v) fmt.Println(s) }
当然,前提是切片和数字的长度和类型都要对的上。否则会出现如下报错:
panic: runtime error: cannot convert slice with length 5 to array or pointer to array with length 6 goroutine 1 [running]: main.main() /tmp/sandbox1162344488/prog.go:9 +0x1d Program exited.
总结
在本次 Go1.20 的更新中,比较有意思的是 PGO 的预览版本,大家有机会可以体验下不改代码就提高应用性能的快感。而相关的更新有的是在偿还技术债务。例如:编译加速等。
原本關注度很高的 arean,之前在《打臉了兄弟們,Go1.20 arena 來了! 》中我分享過。在 Go 團隊在具體實作和分析後,發現現有的 API 有嚴重的問題,暫時回滾迭代程式碼了,因此放了鴿子。這塊我計劃後面再單獨分享。
尤其要注意的,Go1.21 起將不再支援 macOS、windows 部分版本。可能有些公司的機器,甚至自己的要提前升級了
以上是Go1.20 那些事:PGO、編譯速度、錯誤處理等新特性,你知道多少?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在Go中,可以使用gorilla/websocket包發送WebSocket訊息。具體步驟:建立WebSocket連線。傳送文字訊息:呼叫WriteMessage(websocket.TextMessage,[]byte("訊息"))。發送二進位訊息:呼叫WriteMessage(websocket.BinaryMessage,[]byte{1,2,3})。

在Go中,函數生命週期包括定義、載入、連結、初始化、呼叫和返回;變數作用域分為函數級和區塊級,函數內的變數在內部可見,而區塊內的變數僅在區塊內可見。

Go和Go語言是不同的實體,具有不同的特性。 Go(又稱Golang)以其並發性、編譯速度快、記憶體管理和跨平台優點而聞名。 Go語言的缺點包括生態系統不如其他語言豐富、文法更嚴格、缺乏動態類型。

在Go中,可以使用正規表示式比對時間戳記:編譯正規表示式字串,例如用於匹配ISO8601時間戳記的表達式:^\d{4}-\d{2}-\d{2}T \d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ 。使用regexp.MatchString函數檢查字串是否與正規表示式相符。

記憶體洩漏會導致Go程式記憶體不斷增加,可通過:關閉不再使用的資源,如檔案、網路連線和資料庫連線。使用弱引用防止記憶體洩漏,當物件不再被強引用時將其作為垃圾回收目標。利用go協程,協程棧記憶體會在退出時自動釋放,避免記憶體洩漏。

使用IDE檢視Go函數文件:將遊標停留在函數名稱上。按下熱鍵(GoLand:Ctrl+Q;VSCode:安裝GoExtensionPack後,F1並選擇"Go:ShowDocumentation")。

在Go中傳遞map給函數時,預設會建立副本,對副本的修改不影響原map。如果需要修改原始map,可透過指標傳遞。空map需小心處理,因為技術上是nil指針,傳遞空map給期望非空map的函數會發生錯誤。

在Golang中,錯誤包裝器允許你在原始錯誤上追加上下文訊息,從而創建新錯誤。這可用於統一不同程式庫或元件拋出的錯誤類型,簡化偵錯和錯誤處理。步驟如下:使用errors.Wrap函數將原有錯誤包裝成新錯誤。新錯誤包含原始錯誤的上下文資訊。使用fmt.Printf輸出包裝後的錯誤,提供更多上下文和可操作性。在處理不同類型的錯誤時,使用errors.Wrap函數統一錯誤類型。
