go - 引用时间 % 12345 的“不稳定值”

标签 go kubernetes

this reflector 包它提到一个不稳定的值被用作名称后缀。它是对 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 的随机数的方法相比,这样做是否有优势?

最佳答案

意思似乎很清楚:

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 map 也出现了类似的情况:

The Go Programming Language Specification

For statements with range clause

The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next.

Go 1 Release Notes

Iterating in maps

The old language specification did not define the order of iteration for maps, and in practice it differed across hardware platforms. This caused tests that iterated over maps to be fragile and non-portable, with the unpleasant property that a test might always pass on one machine but break on another.

In Go 1, the order in which elements are visited when iterating over a map using a for range statement is defined to be unpredictable, even if the same loop is run multiple times with the same map. Code should not assume that the elements are visited in any particular order.

This change means that code that depends on iteration order is very likely to break early and be fixed long before it becomes a problem. Just as important, it allows the map implementation to ensure better map balancing even when programs are using range loops to select an element from a map.

Go 1.3 Release Notes

Map iteration

Iterations over small maps no longer happen in a consistent order. Go 1 defines that “The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next.” To keep code from depending on map iteration order, Go 1.0 started each map iteration at a random index in the map. A new map implementation introduced in Go 1.1 neglected to randomize iteration for maps with eight or fewer entries, although the iteration order can still vary from system to system. This has allowed people to write Go 1.1 and Go 1.2 programs that depend on small map iteration order and therefore only work reliably on certain systems. Go 1.3 reintroduces random iteration for small maps in order to flush out these bugs.

Updating: If code assumes a fixed iteration order for small maps, it will break and must be rewritten not to make that assumption. Because only small maps are affected, the problem arises most often in tests.


类似的担忧导致了一个提议,但没有实现,以确保不稳定排序的顺序是不稳定的:

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

Crazy idea, but what if sort.Sort randomly permuted its input a bit before starting?

Go 1.6 has a different sort.Sort than Go 1.5 and I've seen at least a dozen test failures at Google that were implicitly depending on the old algorithm. The usual scenario is that you sort a slice of structs by one field in the struct. If there are entries with that field equal but others unequal and you expect a specific order for the structs at the end, you are depending on sort.Sort's algorithm. A later sort.Sort might make a different choice and produce a different order. This makes programs not portable from one version of Go to another, much like map hash differences used to make programs not portable from one architecture to another. We solved maps by randomizing the iteration order a bit. In the map case it's not a full permutation, but just enough variation to make tests obviously flaky.

I wonder if we should do the same for sort.Sort. It would only take N swaps to shuffle things quite well, and we already use Nlog(N) swaps, so N(log(N)+1) is not likely to be noticed. That would also protect a bit against malicious inputs.

It would surprise people, especially people who think sort.Sort == sort.Stable. But the rationale is that it's better to surprise them the first time they run the code instead of however many Go releases later.


以下是比较 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
$

关于go - 引用时间 % 12345 的“不稳定值”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51993731/

相关文章:

html - Golang 模板在不同的目录级别上提供 css

go - 在 Go 中解析动态 YAML 的惯用方式是什么?

go - 检查 golang 中的二进制完整性

Kubernetes 驱逐管理器驱逐控制平面 Pod 以回收临时存储

kubernetes - 重新安装 minikube 时 minikube 和 nginx ingress 出现问题

spring-boot - 使用自定义上下文 url 作为环境变量在 minikube 中启动 spring boot

gob.Register 名称未在另一个包中注册接口(interface)

go - 如何在 Go 中访问调用堆栈中的变量

kubernetes - Ingressgateway返回的状态代码与Pod不同

go - 使用 K8S Go 客户端列出 ClusterServiceVersions