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

时间:2018-08-23 20:23:30

标签: go kubernetes

this反射器包中,它提到一个不稳定的值用作名称后缀。这是以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以下随机数的方法相比,这样做有优势吗?

1 个答案:

答案 0 :(得分:1)

含义似乎很清楚:

  

Kubernetes-commit: 1da4f4a745bf536c34e377321a252b4774d1a7e0

     

tools / cache / reflector.go

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

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


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

  

The Go Programming Language Specification

     

对于带有范围子句的语句

     

未指定地图的迭代顺序,因此无法保证   从一个迭代到下一个相同。

     

Go 1 Release Notes

     

在地图中迭代

     

旧的语言规范未定义迭代顺序   对于地图,实际上在不同的硬件平台上有所不同。这个   导致在地图上迭代的测试易碎且不可移植,   具有令人不愉快的特性,即测试可能始终会通过   机器,但又摔坏了。

     

在Go 1中,对元素进行迭代时访问元素的顺序   使用for范围语句的映射被定义为不可预测,甚至   如果同一循环使用同一映射多次运行。代码应   不假定元素以任何特定顺序访问。

     

此更改意味着取决于迭代顺序的代码非常   可能会提早断裂,并在问题变得很严重之前修复。   同样重要的是,它允许地图实现确保更好   地图平衡,即使程序使用范围循环选择   地图中的元素。

     

Go 1.3 Release Notes

     

地图迭代

     

在小地图上的迭代不再以一致的顺序发生。走   1定义为“未指定地图上的迭代顺序,   不能保证每次迭代都相同。”保持   代码,具体取决于地图的迭代顺序,Go 1.0启动了每个地图   在地图中的随机索引处进行迭代。新的地图实现   Go 1.1中引入的功能,忽略了使用   八个或更少的条目,尽管迭代顺序仍然可以变化   从系统到系统。这使人们能够编写Go 1.1和Go   1.2程序依赖于较小的地图迭代顺序,因此只能在某些系统上可靠地运行。 Go 1.3重新引入随机   迭代小地图以清除这些错误。

     

更新:如果代码为小地图假定固定的迭代顺序,则它   将中断,并且必须重写以不做那种假设。因为   只有小地图受到影响,问题最常出现在测试中。


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

  

proposal: sort: return equal values in non-deterministic order#13884

     

这个想法很疯狂,但是如果排序的话会怎样呢?排序对输入进行随机排列   开始之前?

     

Go 1.6的排序方式不同。与Go 1.5的排序不同,我至少看到了   Google的十多次测试失败,这些失败取决于   旧算法。通常的情况是您对结构片段进行排序   通过结构中的一个字段。如果存在与该字段相等的条目   但是其他的不相等,您期望结构的特定顺序为   最后,您要取决于sort.Sort的算法。稍后排序。   可能会做出不同的选择并产生不同的顺序。这个   使程序无法从一个版本的Go移植到另一个版本   就像地图哈希值的差异,这些差异使程序无法从一个平台移植   架构到另一个。我们通过随机化迭代来解决地图   订购一点。在映射情况下,它不是完整的排列,而仅仅是   足够多的变异使测试明显不可靠。

     

我想知道我们是否应该对sort.Sort做同样的事情。只需要N   交换可以很好地洗牌,我们已经使用了Nlog(N)交换,   因此N(log(N)+1)不太可能被注意到。那也将保护   反对恶意输入。

     

这会让人们感到惊讶,尤其是那些认为排序的人。排序==   排序稳定但理由是让他们感到惊讶更好   他们第一次运行代码而不是许多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
$