Go 1.6 發布資訊

Go 1.6 簡介

最新版 Go,1.6,於 1.5 發布後六個月問世。大部分的變動在於語言、執行時間和函式庫的實作。語言規範並無變動。一如往常,此次發布版本維持 Go 1 相容性承諾。我們預期所有 Go 程式幾乎都能繼續編譯並執行,就像先前一樣。

此版本新增了下列功能:64 位元 MIPS 上的 Linux 以及 32 位元 x86 上的 Android 的新移植;定義並強制執行 與 C 共用 Go 指標的規則;HTTP/2 的透明自動支援;以及 範本重複利用 的新機制。

語言變更

此次發布版本並無語言變更。

移植

Go 1.6 新增試驗性的移植至 64 位元 MIPS 上的 Linux(linux/mips64linux/mips64le)。這些移植支援 cgo,但僅限於內部連結。

Go 1.6 也新增了一個試驗性移植至 32 位元 x86 上的 Android(android/386)。

在 FreeBSD 上,Go 1.6 預設使用 clang 而非 gcc 作為外部 C 編譯器。

在 little-endian 64 位元 PowerPC 上的 Linux(linux/ppc64le),Go 1.6 現在支援具有外部連結的 cgo,並且功能大致齊全。

在 NaCl 上,Go 1.5 需要 SDK 版本 pepper-41。Go 1.6 新增了對後續 SDK 版本的支援。

在使用 -dynlink-shared 編譯模式的 32 位元 x86 的系統中,特定記憶體參考現在會覆寫 CX 暫存器,因此在手動撰寫組合語言時應避免使用。詳細資料請參閱組合語言文件

工具

Cgo

cgo 有兩個重要變更,以及一個次要變更。

重要的變更為定義與 C 程式碼共用 Go 指標的規則,以確保該 C 程式碼能夠與 Go 的垃圾回收機制共存。簡而言之,Go 和 C 可在「指到該記憶體的指標作為 cgo 呼叫的一部分傳遞給 C」的情況下,共用由 Go 所配置的記憶體,前提是該記憶體本身不包含指到 Go 配置記憶體的指標,且在呼叫返回後,由 C 保留的指標不會存在。這些規則在程式執行期間由時間執行:如果執行時間偵測到違規,則會印出診斷並讓程式崩潰。設定環境變數 GODEBUG=cgocheck=0 能夠停用這些檢查,但請注意,絕大多數被檢查識別的程式碼在各種方式上都與垃圾回收機制有不合的地方。停用這些檢查通常只會導致較難理解的錯誤模式。強烈建議修正相關程式碼,而不是關閉這些檢查。有關更多詳細資訊,請參閱cgo 文件

次要的變更為加入明確的 C.complexfloatC.complexdouble 型別,與 Go 的 complex64complex128 分開。與其他數字型別一樣,C 的複雜型別和 Go 的複雜型別不再可互換。

編譯器工具鏈

編譯器工具鏈幾乎沒有改變。在內部,最重要的變更為剖析器現在為親自撰寫,不再從 yacc 產生。

編譯器、連結器和 go 指令有一個新旗標 -msan,類似 -race 且僅在 linux/amd64 中可用,可以啟用與Clang MemorySanitizer 的互通。這種互通主要用於測試包含可疑 C 或 C++ 程式碼的程式。

連結器有一個新選項 -libgcc,連結cgo 程式碼時,可設定 C 編譯器支援函式庫預期位置。在使用時才會查詢此選項 -linkmode=internal,並可將其設定為 none 以停用支援函式庫。

組建模式 (在 Go 1.5 中開始) 的實作已擴充至更多系統。此版本增加了對 android/386android/amd64android/arm64linux/386linux/arm64c-shared 模式支援,對 linux/386linux/armlinux/amd64linux/ppc64leshared 模式支援;還有 android/386android/amd64android/armandroid/arm64linux/386linux/amd64linux/armlinux/arm64linux/ppc64le 的新 pie 模式支援 (產生與位置無關的可執行檔)。詳細資訊請參閱設計文件

提醒您,連結器的 -X 記號已在 Go 1.5 中變更。在 Go 1.4 及更早的版本中,它接受兩個引數,如下

-X importpath.name value

Go 1.5 新增另一種語法使用單一引數,它本身就是 名稱=值

-X importpath.name=value

在 Go 1.5 的版本中,舊語法仍然可以接受,列印出建議使用新語法的警告訊息後。Go 1.6 仍然接受舊語法,並列印警告。Go 1.7 將移除對舊語法的支援。

Gccgo

GCC 及 Go 專案的版本計畫並不一致。GCC 版本 5 包含 gccgo 的 Go 1.4 版本。下一個版本,GCC 6,將會有 gccgo 的 Go 1.6.1 版本。

Go 指令

go 指令的基本操作仍然沒有改變,但是有些變更是值得注意的。

Go 1.5 引進對供應商的實驗性支援,透過將 GO15VENDOREXPERIMENT 環境變數設定為 1 來啟用。Go 1.6 保留供應商的支援,不再視為實驗性質,並預設啟用。您可以透過將 GO15VENDOREXPERIMENT 環境變數設定為 0 來明確停用。Go 1.7 將移除對環境變數的支援。

預設啟用供應商最可能會在包含現有命名為 供應商 目錄(不預期根據新的供應商語意來詮釋)的原始碼樹中造成問題。在這種情況下,最簡單的解決方法是將目錄名稱變更為 供應商 以外的任何名稱,並更新任何受影響的匯入路徑。

有關供應商的詳細資訊,請參閱 go 指令設計文件 的文件。

有一個新的建置標記,-msan,它會編譯具有支援 LLVM 記憶消毒功能的 Go。這主要是打算在連結對照使用記憶消毒來檢查的 C 或 C++ 程式碼時使用。

Go 文件指令

Go 1.5 引進 go 文件 指令,它允許僅使用套件名稱來參照套件,如 go 文件 http。如果發生歧義,Go 1.5 的行為是使用字典序最早的匯入路徑的套件。在 Go 1.6 中,歧義會透過偏好具有較少元素的匯入路徑來解決,並使用字典序比較來打破僵局。此變更的一個重要影響是,現在偏愛套件的原始副本,而不偏愛供應商的副本。成功的搜尋也傾向於執行得更快。

Go vet 指令

go vet 指令現在會診斷將函式或方法值傳遞作為 Printf 的引數,例如傳遞 f,而 f() 是預期的。

效能

一如往常,變更非常一般且差異很大,因此難以的確切說明效能。某些程式可能會執行得更快,某些程式則會執行得更慢。平均而言,Go 1 效能基準測試套件中的程式在 Go 1.6 的執行速度比在 Go 1.5 時快了幾個百分點。垃圾回收暫停時間甚至比 Go 1.5 時更短,尤其是對於使用大量記憶體的程式。

已經進行重大最佳化,對於下列套件的實作帶來超過 10% 的改善:compress/bzip2compress/gzipcrypto/aescrypto/ellipticcrypto/ecdsasort

標準函式庫

HTTP/2

Go 1.6 在 net/http 套件中為新的 HTTP/2 協定 加入透明支援。使用 HTTPS 時,Go 執行個體和伺服器將自動在適當時使用 HTTP/2。沒有針對 HTTP/2 協定處理之詳細資訊而匯出的 API,就像沒有針對 HTTP/1.1 而匯出的 API 一樣。

必須停用 HTTP/2 的程式可以透過設定 Transport.TLSNextProto(對於執行個體)或 Server.TLSNextProto(對於伺服器)為非 nil 的空地圖來做到。

必須調整 HTTP/2 協定特定詳細資訊的程式可以匯入並使用 golang.org/x/net/http2,尤其是它的 ConfigureServerConfigureTransport 函式。

執行時期

執行時期已加入輕量級的最佳化 प्रयास,用來偵測並發程式碼濫用地圖。一如往常一樣,如果一個 goroutine 寫入一個地圖,就不應有任何其他 goroutine 同時讀取或寫入該地圖。如果執行時期偵測到此情況,它會印出一份診斷結果,然後讓程式發生故障。找出此問題的最佳方式是使用 競爭偵測器 執行程式,它將更加可靠地識別競爭條件並提供更詳細的資訊。

對於會終止程式的意外事件,執行時期現在預設只會印出執行中 goroutine 的堆疊,而不是所有現有的 goroutine。通常只有一個目前的 goroutine 與意外事件有關,因此遺漏其他 goroutine 可大幅減少發生故障訊息中的無關輸出。若要於故障訊息中看到所有 goroutine 的堆疊,請將環境變數 GOTRACEBACK 設定為 all,或在發生故障前呼叫 debug.SetTraceback,然後重新執行程式。請參閱 執行時期文件以瞭解詳細資訊。

更新:預計轉儲整個程式狀態的未捕捉到錯誤,例如偵測到逾時或明確處理接收到的訊號時,現在應先呼叫 debug.SetTraceback("all"),然後才發生錯誤。搜尋 signal.Notify 的用途可能有助於找出這種程式碼。

在 Windows 上,Go 1.5 及稍早版本的 Go 程式會在啟動時透過呼叫 timeBeginPeriod(1) 將整體 Windows 計時器解析度強制設定為 1ms。Go 不再需要此動作來獲得良好的排程器效能,而變更整體計時器解析度會在某些系統上造成問題,因此已移除這項呼叫。

使用 -buildmode=c-archive-buildmode=c-shared 來建置封存或共享函式庫時,訊號處理已經變更。在 Go 1.5 中,封存或共享函式庫會為大多數訊號安裝訊號處理常式。在 Go 1.6 中,將只會為同步訊號安裝訊號處理常式,以處理 Go 程式碼中的執行時期錯誤:SIGBUS、SIGFPE、SIGSEGV。查看 os/signal 套件以取得更多詳細資料。

反射

reflect 套件已 解決 gc 與 gccgo 工具鏈之間的長期不相容性,其關於包含匯出的欄位的嵌入式未匯出結構體類型。使用反射來存取資料結構的程式碼,尤其是在遵循 encoding/jsonencoding/xml 套件的精神實作序列化的程式碼,可能需要更新。

當使用反射在嵌入式未匯出結構體類型欄位中存取該結構體的匯出欄位時,就會產生問題。在此情況下,reflect 錯誤地將嵌入式欄位報告為匯出,但回傳一個空的 Field.PkgPath。現在,它會正確地將欄位報告為未匯出,但在評估存取結構體內包含的匯出欄位時,會忽略此事實。

更新:通常,先前遍歷結構體並使用

f.PkgPath != ""

來排除無法存取的欄位的程式碼,現在應使用

f.PkgPath != "" && !f.Anonymous

例如,請參閱 encoding/jsonencoding/xml 的實作變更。

排序

sort 套件中,Sort 的實作已被改寫,以減少大約 10% 對 InterfaceLessSwap 方法的呼叫,並產生相應的整體時間節省。新的演算法確實會對比較相等的數值(這些配對 Less(i, j)Less(j, i) 為 false)選擇與之前不同的排序方式。

更新中Sort 的定義不保證相等值最後的順序,但新的行為仍可能中斷期待特定順序的程式。此類程式應該修改其 Less 實作以回報想要的順序,或應該切換到會保留相等值原始輸入順序的 Stable

範本

text/template 套件中,有兩個重要的新功能可簡化範本撰寫工作。

首先,現在可以 調整範本動作周圍的空白,可讓範本定義更易讀。動作開頭的減號表示在動作前移除空白,而動作結尾的減號表示在動作後移除空白。例如,範本

{{23 -}}
   <
{{- 45}}

格式化為 23<45

其次,新的 {{block}} 動作,加上允許重新定義命名範本,提供定義範本區塊的簡單方式,這些範本區塊可在不同的實例化中取代。text/template 套件中有一個 範例 展示此新功能。

函式庫的次要變更