Go 1.3 發行版本說明

Go 1.3 簡介

最新的 Go 發行版 1.3 在 1.2 之後半年推出,並不包含語言變更。它主要專注在實作工作上,例如提供精確的垃圾回收,大幅修改編譯工具鏈以加速建置速度(尤其是大型專案),全面的大幅效能改善,以及支援 DragonFly BSD、Solaris、Plan 9 和 Google 的原生客戶端架構 (NaCl)。它也對同步的記憶體模式進行了重要的改良。一如往常,Go 1.3 維持了相容性承諾,且幾乎所有內容在移轉到 1.3 後仍可以繼續編譯和執行,無需更動。

受支援作業系統和架構的變更

移除對 Windows 2000 的支援

Microsoft 於 2010 年停止支援 Windows 2000。由於它針對例外處理(類 Unix 用語中的訊號)有實作困難,因此從 Go 1.3 開始,Go 也將不再支援。

支援 DragonFly BSD

Go 1.3 現在包括對 DragonFly BSD 的實驗性支援,適用於 amd64(64 位元 x86)和 386(32 位元 x86)架構。它使用 DragonFly BSD 3.6 或更新版本。

FreeBSD 的支援

當時並未宣佈,但自 Go 1.2 發行以來,對 FreeBSD 中的 Go 支援需要 FreeBSD 8 或更新版本。

自 Go 1.3 起,對 FreeBSD 中的 Go 支援需要設定旗標 COMPAT_FREEBSD32 來編譯核心。

在與 ARM 平臺上切換為 EABI 系統呼叫的同時,Go 1.3 將只在 FreeBSD 10 上執行。x86 平臺(386 和 amd64)不受影響。

原生客戶端的支援

使用 1.3 發行版本後,對原生客戶端虛擬機器架構的支援已重新回到 Go。它可以在 32 位元 Intel 架構(GOARCH=386)上執行,也可以在 64 位元 Intel 上執行(但使用 32 位元指標,即 GOARCH=amd64p32)。尚未支援 ARM 上的原生客戶端。請注意,這是原生客戶端(NaCl),而不是可攜式原生客戶端(PNaCl)。原生客戶端的詳細訊息 在此;如何設定 Go 的版本 在此 說明。

NetBSD 的支援

自 Go 1.3 起,對 NetBSD 中的 Go 支援需要 NetBSD 6.0 或更新版本。

OpenBSD 的支援

自 Go 1.3 起,對 OpenBSD 中的 Go 支援需要 OpenBSD 5.5 或更新版本。

計劃 9 的支援

Go 1.3 現在包括對 386(32 位元 x86)架構上計劃 9 的實驗性支援。它需要自 2012 年 6 月起即存在於計劃 9 中的 Tsemacquire 系統呼叫。

Solaris 的支援

Go 1.3 現在包括對 amd64(64 位元 x86)架構上 Solaris 的的實驗性支援。它需要 illumos、Solaris 11 或更新版本。

記憶體模型的變更

Go 1.3 記憶體模型 增加一條新規則,關於在快取頻道傳送與接收,明確說明快取頻道可以用作簡單的旗標,使用傳送至頻道來取得,以及接收自頻道來釋放。這不是語言的變動,僅是對必要的溝通屬性作進一步說明。

執行環境和工具的變更

堆疊

Go 1.3 已將 goroutine 堆疊的實作從舊的「分段」模型改為連續模型。當 goroutine 需要更多堆疊時,它的堆疊會被轉移至一塊較大的單一記憶體區塊。此轉移作業的負擔很好地得到攤銷,並消除了計算不斷跨越區段邊界的舊「熱點」問題。包括效能數據在內的詳細資訊請參閱此 設計文件

垃圾回收程式的變更

一段時間以來,垃圾回收程式在檢查堆疊中的值時一直是「精確」的;Go 1.3 版本增加了在堆疊中值的等效精確度。這表示一個諸如整數一般的非指標 Go 值絕不會被誤認為指標,而阻止未使用記憶體被清除。

從 Go 1.3 開始,執行時間假設指標類型值包含指標,而其他值不包含指標。此假設是堆疊擴充和垃圾回收精確行為的基礎。使用 package unsafe 在指標類型值中儲存整數的程式是非法的,在執行時間偵測到該行為時會當機。使用 package unsafe 在整數類型值中儲存指標的程式也是非法的,但是在執行期間較難診斷。因為指標被隱藏於執行時間,堆疊擴充或垃圾回收可能會清除它們指向的記憶體,建立 懸浮指標

更新:使用 unsafe.Pointer 將儲存在記憶體中的整數類型值轉換成指標的程式是非法的,必須重新編寫。該程式碼可以藉由 go vet 找出。

Map 迭代

在小型 map 中進行的迭代不再以一致順序發生。Go 1 定義「迭代 map 的順序未指定,且不保證每次迭代都是相同的。」為避免程式依賴 map 迭代順序,Go 1.0 從 map 中的隨機索引開始進行每個 map 迭代。Go 1.1 中引進的新 map 實作並未針對包含八個或以下條目的 map 進行迭代隨機化,儘管迭代順序在不同的系統間可能有所不同。這讓人們得以撰寫依賴小型 map 迭代順序的 Go 1.1 和 Go 1.2 程式,因此僅能在特定系統上穩定執行。Go 1.3 重新引進小型 map 的隨機迭代,以清除這些錯誤。

更新:若程式碼假設小型地圖有固定迭代順序,將會中斷函式並必須重寫,不進行此假設。由於僅有小型地圖受影響,此問題最常在測試中出現。

作為 Go 連結器整體翻修的一部份,編譯器和連結器已經過重構。連結器仍然是 C 程式,但現在連結器中指令選取階段已透過建立一個名為 liblink 的新函式庫移到編譯器中。在軟體套件第一次編譯時,只要執行一次指令選取,就能夠大幅提升大型專案的編譯速度。

更新:雖然這是重大內部變更,但不應對程式有任何影響。

gccgo 的狀態

GCC 4.9 版將包含 Go 1.2 (而非 1.3) 版本的 gccgo。GCC 和 Go 專案的發行時程並不同步,這代表 1.3 版會在開發分支中提供,但下一個 GCC 版本 4.10 可能會有 Go 1.4 版本的 gccgo。

go 命令變更

cmd/go 命令有幾個新功能。go rungo test 子命令支援新的 -exec 選項,用於指定執行結果二進位檔的替代方式。它的立即目的就是要支援 NaCl。

go test 子命令的測試範圍支援,現在會在啟用競爭偵測時自動將範圍模式設定為 -atomic,以消除有關對範圍計數器的 unsafe 存取的錯誤報告。

go test 子命令現在總是會建置軟體套件,即使它沒有測試檔案。先前,若沒有測試檔案,它就不會執行任何動作。

go build 子命令支援新的 -i 選項,用於安裝指定目標的依存,但不安裝目標本身。

現在支援使用已啟用的 cgo 進行異地編譯。在執行 all.bash 時, CC_FOR_TARGET 和 CXX_FOR_TARGET 環境變數用於分別指定 C 和 C++ 碼的異地編譯器。

最後,go 命令現在支援透過 cgo 匯入 Objective-C 檔案 (加 .m 字尾) 的軟體套件。

cgo 的變更

用 Go 套件處理 import "C" 宣告的 cmd/cgo 指令已修正一項可能會導致某些套件停止編譯的嚴重 bug。以前,指向未完成結構類型的所有指標都會轉譯為 Go 類型 *[0]byte,其結果是 Go 編譯器無法診斷通過與函數預期的另一項不同結構指標。Go 1.3 透過將每個不同的未完成結構轉譯為不同的命名類型來修正此錯誤。

指定不完整的 struct S 進行 C 宣告 typedef struct S T 後,某些 Go 程式碼會利用此 bug 來交換參照 C.struct_SC.T 類型。現在,Cgo 明確允許使用此功能,即使對於已完成的結構類型也是如此。然而,某些 Go 程式碼也會利用此 bug 從一個套件傳遞 *C.FILE(例如)到另一個套件。這是非法的,而且已不再適用:通常,Go 套件應避免在自己的 API 中公開 C 類型和名稱。

更新:混淆指標指向不完整類型或透過套件邊界傳遞指向不完整類型的程式碼將無法再進行編譯,而且必須改寫。如果轉換正確且必須保留,請使用透過 unsafe.Pointer 的明確轉換。

使用 SWIG 的程式需要 SWIG 3.0

對於使用 SWIG 的 Go 程式,現在需要使用 SWIG 版本 3.0。cmd/go 指令現在會直接將 SWIG 產生的物件檔案連結到執行檔,而不是用共用程式庫建置和連結。

命令列旗標分析

在 gc 工具鏈中,組譯器現在使用與 Go 旗標套件相同的命令列旗標分析規則,這與傳統的 Unix 旗標分析不同。這可能會影響直接呼叫工具的指令碼。例如,go tool 6a -SDfoo 現在必須寫成 go tool 6a -S -D foo。(相同的變更已套用在 Go 1.1 的編譯器和連結器中。)

對 godoc 的變更

在使用 -analysis 旗標呼叫後,godoc 現在會針對索引代碼執行進階的 靜態分析。分析結果會顯示於原始程式碼檢視和套件文件檢視中,其中包括每個套件的呼叫圖,以及定義和參考、類型和方法、介面和實作、通道上的傳送和接收操作、函數和呼叫函數,以及呼叫位置和被呼叫函數之間的關係。

其他

用來比較效能基準執行結果的程式 misc/benchcmp 已被改寫。它最初是主儲存庫中的 shell 和 awk 指令碼,現在則是 go.tools 儲存庫中的 Go 程式。文件 在此

對於我們當中建置 Go distribution 的少數人來說,工具 misc/dist 已搬移並更名,現在位於 misc/makerelease,仍在主儲存庫。

效能

由於執行時期和垃圾回收機制的變更,加上對函式庫的一些變更,因此這個版本 Go 二進位檔案的效能已在許多情況下得到改善。顯著的範例包括

此外,執行階段現在會在堆疊傾印中包含 goroutine 已被封鎖多久,這在除錯死結或效能問題時可能是有用的資訊。

標準函式庫的變更

新增套件

已將一個新的套件 debug/plan9obj 新增到標準函式庫。它實作對 Plan 9 a.out 物件檔案存取。

函式庫的主要變更

先前 crypto/tls 中有一個 bug 導致可能在 TLS 中無意間略過驗證。在 Go 1.3 中,該 bug 已修正:您必須指定伺服器名稱或 InsecureSkipVerify,且如果指定伺服器名稱時需強制執行。這可能會損壞依賴於不安全行為的現有程式碼。

標準函式庫新增了一個重要的新類型:sync.Pool。它提供了一個有效率的機制來實作某種類型的快取,而其記憶體可由系統自動回收。

現在 testing 套件的基準測試輔助工具 BRunParallel 方法,讓執行基準測試(使用多個 CPU)變得更容易。

更新:crypto/tls 修正程式可能會損壞現有的程式碼,但此類程式碼是有錯誤的,應加以更新。

函式庫的次要變更

下表摘要了函式庫的一些次要變更,主要是新增功能。有關每個變更的更多資訊,請參閱相關的套件文件。