1 回答

TA貢獻1884條經驗 獲得超4個贊
意思似乎很清楚:
Kubernetes 提交:1da4f4a745bf536c34e377321a252b4774d1a7e0
工具/緩存/反射器.go
// reflectorDisambiguator is used to disambiguate started reflectors. // initialized to an unstable value to ensure meaning isn't attributed to the suffix.
后綴行為不應該是確定性的,因為您不應該依賴特定的實現行為。
例如,類似的情況發生在 Go 地圖上:
對于帶有范圍子句的語句
未指定地圖上的迭代順序,并且不保證從一次迭代到下一次迭代是相同的。
在地圖中迭代
舊的語言規范沒有定義地圖的迭代順序,實際上它在不同的硬件平臺上是不同的。這導致在地圖上迭代的測試變得脆弱且不可移植,并且具有令人不快的特性,即測試可能總是在一臺機器上通過但在另一臺機器上失敗。
在 Go 1 中,使用 for range 語句遍歷映射時訪問元素的順序被定義為不可預測,即使同一個循環使用同一個映射運行多次也是如此。代碼不應假定以任何特定順序訪問元素。
此更改意味著依賴于迭代順序的代碼很可能會提前中斷并在成為問題之前很久就得到修復。同樣重要的是,即使程序使用范圍循環從地圖中選擇元素,它也允許地圖實現確保更好的地圖平衡。
地圖迭代
小地圖上的迭代不再以一致的順序發生。Go 1 定義“未指定映射的迭代順序,并且不保證從一個迭代到下一個迭代是相同的。” 為了避免代碼依賴于地圖迭代順序,Go 1.0 在地圖中的隨機索引處開始每個地圖迭代。Go 1.1 中引入的新 map 實現忽略了對具有 8 個或更少條目的 map 進行隨機迭代,盡管迭代順序仍然因系統而異。這允許人們編寫依賴于小地圖迭代順序的 Go 1.1 和 Go 1.2 程序,因此只能在某些系統上可靠地工作。Go 1.3 重新引入了小地圖的隨機迭代,以消除這些錯誤。
更新:如果代碼假定小地圖的迭代順序是固定的,它將中斷并且必須重寫以不做出該假設。因為只有小地圖受到影響,所以問題最常出現在測試中。
類似的擔憂導致了一項未實施的提案,以確保不穩定排序的順序是不穩定的:
瘋狂的想法,但是如果 sort.Sort 在開始之前隨機排列它的輸入呢?
Go 1.6 的 sort.Sort 與 Go 1.5 不同,我在谷歌看到至少有十幾個測試失敗是隱含地依賴于舊算法。通常的情況是您按結構中的一個字段對一片結構進行排序。如果存在該字段相等但其他不相等的條目,并且您希望最后的結構具有特定順序,則您依賴于 sort.Sort 的算法。稍后的 sort.Sort 可能會做出不同的選擇并產生不同的順序。這使得程序無法從一個版本的 Go 移植到另一個版本,就像用于使程序無法從一種體系結構移植到另一種體系結構的映射哈希差異一樣。我們通過稍微隨機化迭代順序來解決地圖問題。在 map 的情況下,它不是一個完整的排列,而是足以使測試明顯不穩定的變化。
我想知道我們是否應該對 sort.Sort 做同樣的事情。只需要 N 次交換就可以很好地洗牌,而且我們已經使用了 Nlog(N) 次交換,所以 N(log(N)+1) 不太可能被注意到。這也可以防止惡意輸入。
這會讓人們感到驚訝,尤其是那些認為 sort.Sort == sort.Stable 的人。但理由是,最好是在他們第一次運行代碼時讓他們感到驚訝,而不是在以后發布許多 Go 版本。
以下是time.Now()
與以下各項相比的基準rand.Intn()
:
package main
import "testing"
import (
rand "math/rand"
"time"
)
// https://github.com/kubernetes/client-go/blob/79cb21f5b3b1dd8f8b23bd3f79925b4fda4e2562/tools/cache/reflector.go#L100
var reflectorDisambiguator = int64(time.Now().UnixNano() % 12345)
func BenchmarkTimeNow(b *testing.B) {
for N := 0; N < b.N; N++ {
reflectorDisambiguator = int64(time.Now().UnixNano() % 12345)
}
}
// rand.Intn()
func init() {
rand.Seed(time.Now().UnixNano())
reflectorDisambiguator = int64(rand.Intn(12345))
}
func BenchmarkRandIntn(b *testing.B) {
for N := 0; N < b.N; N++ {
rand.Seed(time.Now().UnixNano())
reflectorDisambiguator = int64(rand.Intn(12345))
}
}
輸出:
$ go test disambiguator_test.go -bench=.
goos: linux
goarch: amd64
BenchmarkTimeNow-4 20000000 67.5 ns/op
BenchmarkRandIntn-4 100000 11941 ns/op
$
- 1 回答
- 0 關注
- 114 瀏覽
添加回答
舉報