为了账号安全,请及时绑定邮箱和手机立即绑定

参考时间 % 12345 的“不稳定值”

参考时间 % 12345 的“不稳定值”

Go
冉冉说 2023-03-21 17:33:51
在这个反射器包中,它提到了一个不稳定的值被用作名称后缀。它是对 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 回答

?
慕村9548890

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 编程语言规范

对于带有范围子句的语句

未指定地图上的迭代顺序,并且不保证从一次迭代到下一次迭代是相同的。

Go 1 发行说明

在地图中迭代

旧的语言规范没有定义地图的迭代顺序,实际上它在不同的硬件平台上是不同的。这导致在地图上迭代的测试变得脆弱且不可移植,并且具有令人不快的特性,即测试可能总是在一台机器上通过但在另一台机器上失败。

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

此更改意味着依赖于迭代顺序的代码很可能会提前中断并在成为问题之前很久就得到修复。同样重要的是,即使程序使用范围循环从地图中选择元素,它也允许地图实现确保更好的地图平衡。

Go 1.3 发行说明

地图迭代

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

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


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

建议:排序:以非确定性顺序返回相等值#13884

疯狂的想法,但是如果 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

$


查看完整回答
反对 回复 2023-03-21
  • 1 回答
  • 0 关注
  • 205 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号