相对于时间%12345的“不稳定值”

布莱恩:

反射器包中,提到了一个不稳定的值用作名称后缀。它是以12345为模的纳秒数。这是否有意义?或者它只是伪随机的同义词,因此人类不解释它?

// reflectorDisambiguator is used to disambiguate started reflectors.
// initialized to an unstable value to ensure meaning isn't attributed to the suffix.
var reflectorDisambiguator = int64(time.Now().UnixNano() % 12345)

“不稳定”一词是什么让我不确定。在这种情况下是什么意思?

与另一种在12345以下获得随机数的方法相比,这样做有优势吗?

peterSO:

含义似乎很清楚:

Kubernetes提交:1da4f4a745bf536c34e377321a252b4774d1a7e0

工具/缓存/reflector.go

// reflectorDisambiguator is used to disambiguate started reflectors.
// initialized to an unstable value to ensure meaning isn't attributed to the suffix.

后缀行为不应是确定性的,因为您不应依赖于特定的实现行为。


例如,Go地图发生了类似情况:

Go编程语言规范

对于带有范围子句的语句

未指定地图的迭代顺序,并且不能保证每次迭代之间都相同。

Go 1发行说明

在地图中迭代

旧的语言规范没有定义地图的迭代顺序,实际上,它在各个硬件平台上都不同。这导致对地图进行迭代的测试是脆弱且不可移植的,具有令人不愉快的特性,即测试可能始终在一台计算机上通过而在另一台计算机上中断。

在Go 1中,即使同一张地图多次运行同一循环,使用for range语句遍历一个地图时元素被访问的顺序也被定义为不可预测。代码不应假定以任何特定顺序访问元素。

这种变化意味着依赖于迭代顺序的代码很可能会提前中断,并在问题出现之前很长时间就被修复。同样重要的是,即使程序正在使用范围循环从地图中选择元素,它也允许地图实现确保更好的地图平衡。

Go 1.3发行说明

地图迭代

小地图上的迭代不再以一致的顺序发生。Go 1定义为“未指定地图上的迭代顺序,并且不能保证每次迭代之间都相同。” 为了避免代码依赖于地图迭代顺序,Go 1.0在地图中的随机索引处开始了每个地图迭代。Go 1.1中引入的新地图实现忽略了对具有八个或更少条目的地图进行随机化迭代的方法,尽管迭代顺序仍可能因系统而异。这使人们能够编写依赖于小的地图迭代顺序的Go 1.1和Go 1.2程序,因此只能在某些系统上可靠地工作。Go 1.3重新引入了针对小地图的随机迭代,以清除这些错误。

更新:如果代码为小地图假设固定的迭代顺序,则它将破坏并且必须重写以不作此假设。因为只影响小的地图,所以该问题最常出现在测试中。


类似的担忧导致提出了一项提案,该提案尚未实施,以确保不稳定排序的顺序不稳定:

提案:排序:以不确定的顺序返回相等的值#13884

疯狂的想法,但是如果排序。排序在开始之前随机排列一下其输入呢?

Go 1.6的排序方式与Go 1.5不同,我在Google上看到至少十几次测试失败,这些失败隐含地取决于旧算法。通常的情况是,您按结构中的一个字段对结构切片进行排序。如果存在该字段相等的条目,但其他条目不相等,并且您期望最后的结构具有特定的顺序,则取决于sort.Sort的算法。稍后的排序。排序可能会做出不同的选择并产生不同的顺序。这使得程序无法从Go的一个版本移植到另一版本,就像用于使程序不能从一种体系结构移植到另一种体系结构的映射哈希差异一样。我们通过随机化迭代顺序来解决映射。在映射的情况下,它不是完整的排列,而是足够的变化以使测试明显不稳定。

我想知道我们是否应该对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
$

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章