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 run
和 go 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_S
和 C.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 二進位檔案的效能已在許多情況下得到改善。顯著的範例包括
- 執行時期能更有效率地處理 defer,減少每一個呼叫 defer 的 goroutine 約兩千位元的記憶體使用量。
- 垃圾回收機制已經過加速,使用並行的掃描演算法、更好的並行化和更大的頁面。累積效應可將收集器暫停時間減少 50-70%。
- 競爭偵測器(請參閱此指南)現在快了大約 40%。
- 對於某些簡單運算式來說,正規運算式套件
regexp
現在明顯快得多,這是因為已實作第二個一次執行引擎。選擇要使用哪個引擎是自動的;詳細資訊對使用者來說是隱藏的。
此外,執行階段現在會在堆疊傾印中包含 goroutine 已被封鎖多久,這在除錯死結或效能問題時可能是有用的資訊。
標準函式庫的變更
新增套件
已將一個新的套件 debug/plan9obj
新增到標準函式庫。它實作對 Plan 9 a.out 物件檔案存取。
函式庫的主要變更
先前 crypto/tls
中有一個 bug 導致可能在 TLS 中無意間略過驗證。在 Go 1.3 中,該 bug 已修正:您必須指定伺服器名稱或 InsecureSkipVerify,且如果指定伺服器名稱時需強制執行。這可能會損壞依賴於不安全行為的現有程式碼。
標準函式庫新增了一個重要的新類型:sync.Pool
。它提供了一個有效率的機制來實作某種類型的快取,而其記憶體可由系統自動回收。
現在 testing
套件的基準測試輔助工具 B
有 RunParallel
方法,讓執行基準測試(使用多個 CPU)變得更容易。
更新:crypto/tls 修正程式可能會損壞現有的程式碼,但此類程式碼是有錯誤的,應加以更新。
函式庫的次要變更
下表摘要了函式庫的一些次要變更,主要是新增功能。有關每個變更的更多資訊,請參閱相關的套件文件。
- 在
crypto/tls
套件中,新的DialWithDialer
函式使用者可以使用現有的撥號器建立 TLS 連線,這使得能更輕鬆地控制呼叫選項,例如逾時。此套件現在也會在ConnectionState
結構中報告連線所使用的 TLS 版本。 - 現在,
CreateCertificate
函數支援剖析 (以及其他地方的序列) PKCS #10 憑證簽章要求。 fmt
封裝的格式化列印函數現已定義%F
作為列印浮點值時%f
的同義字。math/big
封裝的Int
和Rat
類型現在實作encoding.TextMarshaler
和encoding.TextUnmarshaler
。- 複雜乘冪函數
Pow
現已指定當第一個引數為 0 時的行為。以前未定義。詳細資訊載於 函數文件 中。 net/http
封裝現在公開用於建立用戶端要求之 TLS 連線的屬性,該屬性位於新的Response.TLS
欄位中。net/http
封裝現在允許使用Server.ErrorLog
設定一個選擇性的伺服器錯誤記錄器。預設仍是所有錯誤都會傳送到 stderr。net/http
封裝現在支援使用Server.SetKeepAlivesEnabled
在伺服器上停用 HTTP keep-alive 連線。預設值仍然是伺服器預設做 keep-alive(為多個要求重複使用連線)。只有資源受限的伺服器或在停機過程中才會想要停用它們。net/http
封裝加入一個選擇性的Transport.TLSHandshakeTimeout
設定,以限制 HTTP 用戶端要求等待 TLS 交握完成的延時。現在也預設設定在DefaultTransport
上。- 由 HTTP 用戶端程式碼使用的
net/http
封裝的DefaultTransport
現在預設會啟用 TCP keep-alive。具有 nilDial
欄位的其他Transport
值仍沿用之前的運作方式:不使用 TCP keep-alive。 net/http
套件現在允許對傳入伺服器請求啟用 TCP 保持活動,只要ListenAndServe
或ListenAndServeTLS
已使用。以其他方式啟動伺服器時,TCP 保持活動不會啟用。net/http
套件現在提供一個選用的Server.ConnState
回呼,用於連接伺服器連線生命週期中的不同階段(請參閱ConnState
)。這可以用於實作速率限制或正常關閉。net/http
套件的 HTTP 用戶端現在有一個選用的Client.Timeout
欄位,用於指定使用用戶端所發出請求的端對端逾時時間。net/http
套件的Request.ParseMultipartForm
方法現在會回傳錯誤,如果主體的Content-Type
不是multipart/form-data
。Go 1.3 之前,會靜默失敗並回傳nil
。倚賴舊有行為的程式碼應予更新。- 在
net
套件中,Dialer
結構現在有一個KeepAlive
選項,用於指定連線的保持活動期間。 net/http
套件的Transport
現在會一致地關閉Request.Body
,即使在發生錯誤時也會。os/exec
套件現在實作與文件內容始終一致的相關二進制檔相對路徑。特別地,它只會在二進制檔的文件名不包含任何路徑分隔符號時才呼叫LookPath
。reflect
套件中的SetMapIndex
函式在從nil
地圖中刪除時不再引發異常。- 如果主執行緒呼叫
runtime.Goexit
,且所有其他執行緒都已執行完畢,現在程式會總是會當掉,並報告偵測到死結。早期的 Go 版本處理這個狀況並不一致:大多數狀況會報告成死結,但有些瑣碎的狀況則會正常退出。 - runtime/debug 套件現在有一個新的的函式
debug.WriteHeapDump
,用於寫出堆疊的說明。 strconv
套件中的CanBackquote
函式現在視DEL
字元U+007F
為非列印字元。syscall
套件現在提供SendmsgN
作為Sendmsg
的替代版本,用於傳回寫入的位元組數。- 在 Windows 上,
syscall
套件現在支援 cdecl 呼叫慣例,方法是在現有函式NewCallback
旁新增新的函式NewCallbackCDecl
。 testing
套件現在會診斷呼叫panic(nil)
的測試,而這幾乎總是錯誤的。此外,即使發生故障,測試現在也會撰寫剖析資料(如果使用剖析標記進行呼叫)。unicode
套件和整個系統中的相關支援已從 Unicode 6.2.0 升級至 Unicode 6.3.0。