Go 1.12中值得關注的幾個變化
Go team如期在2月末版本。從Go 1.12的粗略來看,這個版本相較於之前增加了、的,變化略“小”。這也給下一個版本預留了足夠的“驚喜”空間:)。從目前的plan來看,Go 1.13很可能落地的包括:Go2的幾個proposals:, 和等,以及等。
言歸正傳,我們來看看Go 1.12版本中值得我們關注的幾個變化。
一. Go 1.12的可移植性
Go 1.12一如既往的保持了,使用Go 1.12編譯以往編寫的遺留程式碼,理論上都可以編譯透過並正常執行起來。這是很難得的,尤其是在"Go2"有關proposal逐步落地的“時間節點”,想必Go team為了保持Go1付出了不少額外的努力。
Go語言具有超強的。在Go 1.12中,Go又增加了對aix/ppc64、windows/arm的支援,我們可以在執行於樹莓派3的Windows 10 IoT Core上執行Go程式了。
但是對於一些較老的平臺系統,Go也不想背上較重的包袱。Go也在逐漸“放棄”一些老版本的系統,比如Go 1.12是最後一個支援macOS 10.10、FreeBSD 10.x的版本。在我的一臺Mac 10.9.2的老機器上執行go 1.12將會得到下面錯誤:
$./go version
dyld: Symbol not found: _unlinkat
Referenced from: /Users/tony/.bin/go1.12/bin/./go
Expected in: flat namespace
[1] 2403 trace trap ./go version
二. Go modules機制的最佳化
1. GO111MODULE=on時,獲取go module不再顯式需要go.mod
用過Go 1.11 的童鞋可能都遇到過這個問題,那就是在GO111MODULE=on的情況下(非GOPATH路徑),我要go get某個package時,如果compiler沒有在適當位置找到go.mod,就會提示如下錯誤:
//go 1.11.2
# go get github.com/bigwhite/gocmpp
go: cannot find main module; see 'go help modules'
或
# go get github.com/bigwhite/gocmpp
go: cannot determine module path for source directory /Users/tony/test/go (outside GOPATH, no import comments)
這顯然非常不方便。為了go get 一個package,我還需要顯式地建立一個go.mod檔案。在Go 1.12版本中,這個問題被最佳化掉了。
//go 1.12
# go get github.com/bigwhite/gocmpp
go: finding github.com/bigwhite/gocmpp latest
go: finding golang.org/x/text/encoding/unicode latest
go: finding golang.org/x/text/transform latest
go: finding golang.org/x/text/encoding/simplifiedchinese latest
go: finding golang.org/x/text/encoding latest
go: downloading golang.org/x/text v0.3.0
go: extracting golang.org/x/text v0.3.0
其他在go 1.11.x中對go.mod顯式依賴的命令,諸如go list、go mod download也在Go 1.12版本中和go get一樣不再顯式依賴go.mod。
並且在Go 1.12中go module的下載、解壓操作支援併發進行,前提是go module的Cache路徑:$GOPATH/pkg/mod必須在一個支援file locking的檔案系統中。
2. go.mod中增加go指示欄位(go directive)
go 1.12版本在go.mod檔案中增加了一個go version的指示欄位,用於指示該module內原始碼所使用的 go版本。使用go 1.12建立的go.mod類似下面這樣:
# go mod init github.com/bigwhite/test
go: creating new go.mod: module github.com/bigwhite/test
# cat go.mod
module github.com/bigwhite/test
go 1.12
按照release notes中的說法,如果go.mod中go指示器指示的版本高於你使用的go tool鏈版本,那麼go也會嘗試繼續編譯。如果編譯成功了,那也是ok的。但是如果編譯失敗,那麼會提示:module編譯需要更新版本的go tool鏈。
我們使用go 1.11.4版本go module的程式碼:
// main.go
package main
import (
"fmt"
)
func main() {
fmt.Println("go world")
}
# go build main.go
# ./main
go world
我們看到,雖然go tool chain版本是1.11.4,低於go.mod中的go 1.12,但go 1.11.4仍然嘗試繼續編譯程式碼,並且順利透過。
如果我們將程式碼“故意”修改為下面這樣:
//main.go
package main
import (
"fmt"
)
func main() {
fmt.Printl("go world") // 這裡我們故意將Println寫成Printl
}
再用go 1.11.4編譯這段程式碼:
# go build main.go
# command-line-arguments
./main.go:8:2: undefined: fmt.Printl
note: module requires Go 1.12
我們看到go 1.11.4 compiler提示“需要go 1.12"版本編譯器。從這裡我們看出,我們可以使用go指示器用作module最低version約束的標識。在沒有go指示器時,我們只能在文件上顯式增加這種約束的描述。
不過,這裡有一個小插曲,那就是這種不管go.mod中go版本號是多少,仍然嘗試繼續編譯的機制僅適用於go 1.11.4以及後續高版本。從引入go module的go 1.11到go 1.11.3目前都還不支援這種機制,如果用go 1.11.3嘗試編譯以下上面的程式碼,會得到如下結果:
# go build main.go
go build command-line-arguments: module requires Go 1.12
go 1.11.3不會繼續嘗試編譯,而是在對比當前go tool chain版本與go.mod中go指示器的version後,給出了錯誤的提示並退出。
如果非要使用低於go 1.11.4版本的編譯器去編譯的話,我們可以使用go 1.12工具鏈的go mod edit -go命令來修改一下go.mod中的版本為go 1.11。然後再用go 1.11.4以下的版本去編譯:
# go mod edit -go=1.11
# cat go.mod
module github.com/bigwhite/test
go 1.11
# go build main.go //使用go 1.11.3編譯器
這樣,我們就可用go 1.11~go 1.11.3正常編譯原始碼了。
三. 對binary-only package的最後支援
我在2015的一篇文章 《》中提及到Go的編譯對原始碼的依賴性。對於開源工程中的包,這完全不是問題。但是對於一些商業公司而言,原始碼是公司資產,是不能作為交付物提供給買方的。為此,Go team在中增加了對的機制。
所謂"binary-only package"就是允許開發人員釋出不包含原始碼的二進位制形式的package,並且可直接基於該二進位制package進行編譯。比如下面這個例子:
// 建立二進位制package
# cat $GOPATH/src/github.com/bigwhite/foo.go
package foo
import "fmt"
func HelloGo() {
fmt.Println("Hello,Go")
}
# go build -o $GOPATH/pkg/linux_amd64/github.com/bigwhite/foo.a
# ls $GOPATH/pkg/linux_amd64/github.com/bigwhite/foo.a
/root/.go/pkg/linux_amd64/github.com/bigwhite/foo.a
# mkdir temp
# mv foo.go temp
# touch foo.go
# cat foo.go
//go:binary-only-package
package foo
import "fmt"
# cd $GOPATH
# zip -r foo-binary.zip src/github.com/bigwhite/foo/foo.go pkg/linux_amd64/github.com/bigwhite/foo.a
updating: pkg/linux_amd64/github.com/bigwhite/foo.a (deflated 42%)
adding: src/github.com/bigwhite/foo/foo.go (deflated 11%)
我們將foo-binary.zip釋出到目標機器上後,進行如下操作:
# unzip foo-binary.zip -d $GOPATH/
Archive: foo-binary.zip
inflating: /root/.go/pkg/linux_amd64/github.com/bigwhite/foo.a
inflating: /root/.go/src/github.com/bigwhite/foo/foo.go
接下來,我們就基於二進位制的foo.a來編譯依賴它的包:
//$GOPATH/src/bar.go
package main
import "github.com/bigwhite/foo"
func main() {
foo.HelloGo()
}
# go build -o bar bar.go
# ./bar
Hello,Go
但是經過幾個版本的迭代,Go team發現:,無法保證binary-only package的編譯使用的是與最終連結時相同的依賴版本,這很可能會造成因記憶體問題而導致的崩潰。並且經過調查,似乎用binary-only package的gopher並不多,並且gopher可以使用plugin、shared library、c-shared library等來替代binary-only package,以避免原始碼分發。於是Go 1.12版本將成為支援binary-only package的最後版本。
四. 執行時與標準庫
經過~對執行時,尤其是GC的大幅最佳化和改善後,Go 1.11、Go 1.12對執行時的改善相比之下都是小幅度的。
在Go 1.12中,一次GC後的記憶體分配延遲得以改善,這得益於在大量heap依然存在時清理效能的提升。執行時也會更加積極地將釋放的記憶體歸還給作業系統,以應對大塊記憶體分配無法重用已存在的堆空間的問題。在linux上,執行時使用MADV_FREE釋放未使用的記憶體,這更為高效,作業系統核心可以在需要時重用這些記憶體。
在多CPU的機器上,執行時的timer和deadline程式碼執行效能更高了,這對於提升網路連線的deadline效能大有裨益。
標準庫最大的改變應該算是對的支援了。不過預設不開啟。Go 1.13中將成為預設開啟功能。大多數涉及TLS的程式碼無需修改,使用Go 1.12重新編譯後即可無縫支援TLS 1.3。
另一個”有趣“的變化是syscall包增加了Syscall18,依據syscall包中函式名字慣例,Syscall18支援最多傳入18個引數,這個函式的引入是為了Windows準備的。現在少有程式設計師會設計包含10多個引數的函式或方法了,這估計也是為了滿足Windows中“遺留程式碼”的需求。
五. 工具鏈及其他
1. go安裝包中移除go tour
go tour被從go的安裝包中移除了,Go的安裝包從go 1.4.x開始到go 1.11.x變得日益“龐大”:以linux/amd64的tar.gz包為例,變化趨勢如下:
go 1.4.3: 53MB
go 1.5.4: 76MB
go 1.6.4: 83MB
go 1.7.6: 80MB
go 1.8.7: 96MB
go 1.9.7: 113MB
go 1.10.8: 97MB
go 1.11.5: 134MB
go 1.12: 121MB
後續預計會有更多的非核心功能將會從go安裝包中移除來對Go安裝包進行瘦身,即便不能瘦身,也至少要保持在現有的size水平上。
本次go tour被挪到:
# go get -u golang.org/x/tour
# tour //啟動tour
Go 1.12也是godoc作為web server被內建在Go安裝包的最後一個版本,在Go 1.13中該工具也會被從安裝包中剔除,如有需要,可像go tour一樣透過go get來單獨安裝。
2. Build cache成為必需
build cache在被引入以加快Go包編譯構建速度,但是在Go 1.10和中都可以使用GOCACHE=off關閉build cache機制。但是在Go 1.12中build cache成為必需。如果設定GOCACHE=off,那麼編譯器將報錯:
# GOCACHE=off go build github.com/bigwhite/gocmpp
build cache is disabled by GOCACHE=off, but required as of Go 1.12
3. Go compiler支援-lang flag
Go compiler支援-lang flag,可以指示編譯過程使用哪個版本的Go語法(注意不包括標準庫變化等,僅限於語言自身語法)。比如:
//main.go
package main
import "fmt"
type Int = int
func main() {
var a Int = 5
fmt.Println(a)
}
# go run main.go
5
上面是一個使用了才引入的type alias語法的Go程式碼,我們使用Go 1.12可以正常編譯執行它。但是如果我使用-lang flag,指定使用go1.8語法編譯該程式碼,我們會得到如下錯誤提示:
# go build -gcflags "-lang=go1.8" main.go
# command-line-arguments
./main.go:5:6: type aliases only supported as of -lang=go1.9
換成-lang=go1.9就會得到正確結果:
# go build -gcflags "-lang=go1.9" main.go
# ./main
5
講師主頁:
實戰課:
免費課:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4548/viewspace-2821838/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Go 1.17中值得關注的幾個變化Go
- Go 1.16 中值得關注的幾個變化Go
- C++11 中值得關注的幾大變化(詳解)C++
- 2015年值得關注的幾個WEB技術Web
- Chrome、Edge 齊更新,都有哪些新變化值得關注呢Chrome
- 回顧 2017, Java 有哪些重大變化值得關注?Java
- 網站搜尋引擎優化值得關注的4個策略網站優化
- 8個值得關注的PHP安全函式PHP函式
- C++17中那些值得關注的特性C++
- C++17 中那些值得關注的特性C++
- 值得關注的十個優秀的CSS框架CSS框架
- 你值得關注的幾種常見的js設計模式JS設計模式
- 7 個值得關注的開源雲原生工具
- 8個值得關注的SQL-on-Hadoop框架SQLHadoop框架
- 值得開發者關注的5個新興平臺
- C++17中那些值得關注的特性(上)C++
- 3 月值得關注的 15 個 JavaScript 和 CSS 庫JavaScriptCSS
- 最值得關注的10個C開源專案
- 值得關注的 10 個 Python 英文部落格Python
- 值得關注的10個python語言部落格Python
- macOS版本大升級,這幾項的細節值得你關注Mac
- 掘金上值得關注的 iOS 開發者iOS
- Struts 1.1的Indexed Properties 值得關注Index
- 國內最值得關注的幾大機器人底盤企業機器人
- 20位最值得關注的 JS 開發者JS
- 關於mssql中go等幾個關鍵字的用途及區別SQLGo
- 11個最值得關注的金牌郵件EDM營銷案例
- 程式設計師值得關注的12個國外部落格程式設計師
- 四個值得關注的網際網路理財新模式模式
- RAKsmart美國伺服器低至449元 這幾大特色值得關注伺服器
- Go 1.12 版本的新特性Go
- 認為值得重點關注的技術
- 值得關注的開源軟體推薦
- Java開發者值得關注的7款新工具Java
- 2022年值得關注的5個AI趨勢 – thenewstackAI
- Android開發者2017年最值得關注的25個庫Android
- 13個值得關注的可穿戴式技術發展趨勢
- 2024年值得關注的6個工作場所趨勢