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 关注
- 205 浏览
添加回答
举报
