crypto/randmath/rand
math
math/randfunc Intn(n int) int
RandglobalRand
RandRand
crypto
crypto/randmath/rand
crypto/randmath/rand

一加一大于二

(注意: 参考视频 )

math/randrand.Sourcerand.RandSource
rand.SourceInt63() int64int64rand.Source64uint64
crypto/randrand.Source64
rand.Source64math/randcrypto/randmrandcand
type mySrc struct{}
Seed(...)crypto/rand
func (s *mySrc) Seed(seed int64) { /*no-op*/ }
Uint64()encoding/binarycrypto/randio.Readeruint64
func (s *mySrc) Uint64() (value uint64) {
 binary.Read(crand.Reader, binary.BigEndian, &value)
 return value
}
Int63()Uint64()Uint64()
func (s *mySrc) Int63() int64 {
 return int64(s.Uint64() & ^uint64(1<<63))
}
rand.Source64
var src mrand.Source64
src = &mySrc{}
r := mrand.New(src)
fmt.Printf("%d\n", r.Intn(23))

权衡

math/rand

(注意: 我喜欢在测试中使用质数,所以你会看到许多 7919 作为参数,它是第 1000 个质数。)

math/rand
func BenchmarkGlobal(b *testing.B) {
 for n := 0; n < b.N; n++ {
  result = rand.Intn(7919)
 }
}

还不错!在我的笔记本上大约 38 ns/op。

BenchmarkGlobal-4         50000000        37.7 ns/op
rand.Rand
func BenchmarkNative(b *testing.B) {
 random := rand.New(rand.NewSource(time.Now().UnixNano()))
 for n := 0; n < b.N; n++ {
  result = random.Intn(7919)
 }
}

大约 23 ns/op,相当不错!

BenchmarkNative-4         100000000        22.7 ns/op

现在,让我们测试一下我们写的新种子方案。

func BenchmarkCrypto(b *testing.B) {
 random := rand.New(&mySrc{})
 for n := 0; n < b.N; n++ {
  result = random.Intn(7919)
 }
}
crypto/rand
BenchmarkCrypto-4      2000000       867 ns/op
crypto/rand
func BenchmarkCryptoRead(b *testing.B) {
 buffer := make([]byte, 8)
 for n := 0; n < b.N; n++ {
  result, _ = crand.Read(buffer)
 }
}
crypto/rand
BenchmarkCryptoRead-4      2000000       735 ns/op

我不知道如何做才能进一步提高性能。而且,或许对于你的使用场景来说,花费大约1毫秒来获取非特定随机数不是一个问题。这个需要你自己去评估了。

另外一种思路?

我最熟悉的随机化的用法之一是工具。这样做的目的是在重新连接到有压力的服务器时减少偶然同步的几率,因为有规律的负荷可能会对服务器的恢复造成伤害。在这些场景中,“确定性随机”行为本身不是一个问题,但是在一群实例中使用相同的种子会存在问题。

math/randtime.Now().UnitNano()
crypto/randmath/rand
func NewCryptoSeededSource() mrand.Source {
 var seed int64
 binary.Read(crand.Reader, binary.BigEndian, &seed)
 return mrand.NewSource(seed)
}

我们可以重新对新代码做性能分析,但是我们早已经知道,性能将回到确定性随机的情况下。

func BenchmarkSead(b *testing.B) {
 random := mrand.New(NewCryptoSeededSource())
 for n := 0; n < b.N; n++ {
  result = random.Intn(7919)
 }
}

现在,我们证实了我们的假设是正确的。

BenchmarkSeed-4           50000000        23.9 ns/op

关于作者

嗨,我是内尔·卡彭铁尔。我是旧金山 的资深软件工程师。我已经写了三年的 Go 代码,当快速熟悉了之后,Go 已经成为我最喜欢的语言之一了。

crypto/rand

你可以从获取一份精炼版的代码示例。它遵循 Apache 2.0 授权,所以你可以随意剪切和借鉴任何你需要的代码!


译者:

校对:

本文由 原创编译, 荣誉推出

更多资讯,请关注微信公众号:Go语言中文网