日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

我用 Go 生成的隨機數為什么不隨機?隨機數是怎樣產生的

 

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

這篇文章基于 Go 1.13 版本

Go 實現了兩個包來產生隨機數:

  • 在包 math/rand 的一個偽隨機數生成器( PRNG )
  • 在包 crypto/rand 中實現的加密偽隨機數生成器( CPRNG )

如果這兩個包都產生了隨機數,你需要在真正的隨機數和性能之間尋找平衡。

確定的結果

Go 的 rand 包會使用相同的源來產生一個確定的偽隨機數序列。這個源會產生一個不變的數列,稍后在執行期間使用。將你的程序運行多次將會讀到一個完全相同的序列并產生相同的結果。讓我們用一個簡單的例子來嘗試一下:

func main() {
   for i := 0; i < 4; i++  {
      println(rand.Intn(100))
   }
}

多次運行這個程序將會產生相同的結果:

81
87
47
59

由于源代碼已經發布到 Go 的官方標準庫中,因此任何運行此程序的計算機都會得到相同的結果。但是,由于 Go 僅保留一個生成的數字序列,我們可能想知道 Go 是如何管理用戶請求的時間間隔的。Go 實際上使用此數字序列來播種一個產生這個隨機數的源,然后獲取其請求間隔的模。例如,運行相同的程序,最大值為 10,則模 10 的結果相同。

1
7
7
9

讓我們來看一下如何在每次運行我們的程序時得到不同的序列。

播種

Go 提供一個方法, Seed(see int64) ,該方法能讓你初始化這個默認序列。默認情況下,它會使用變量 1。使用另一個變量將會提供一個新的序列,但會保持確定性:

func main() {
   rand.Seed(2)
   for i := 0; i < 4; i++  {
      println(rand.Intn(100))
   }
}

這些是新的結果:

86
86
92
40

在你每次運行這個程序時,這個序列將會保持不變。這是構建此序列的工作流:

我用 Go 生成的隨機數為什么不隨機?隨機數是怎樣產生的

 

The sequence is pre-generated at the bootstrap

獲取一個全新序列的解決方案是使用一個在運行時能改變的變量,比如當前時間:

func main() {
   rand.Seed(time.Now().UnixNano())
   for i := 0; i < 3; i++  {
      println(rand.Intn(100))
   }
}

由于當前納秒數在任何時刻都是不同的,因此這個程序每次運行都會使用一個不同的序列。然而,盡管這個序列在每次運行都是不同的,可這些數字仍是偽隨機數。如果你準備犧牲性能來獲得更好的隨機性,那么 Go 已經為你提供了另一種實現方式。

隨機數生成器

Go 的標準庫也提供了一個適用于加密應用的隨機數生成器。因此,理所當然的,生成的隨機數并不固定,并且一定會提供更好的隨機性。這有一個例子使用了這個新包 cryto/rand :

func main() {
   for i := 0; i < 4; i++  {
      n, _ := rand.Int(rand.Reader, big.NewInt(100))
      println(n.Int64())
   }
}

這是結果:

12
24
56
19

多次運行這個程序將會得到不同的結果。在內部,Go 應用了如下規則:

在 linux 和 FreeBSD 系統上,Reader 會使用 getrandom(2) (如果可用的話),否則使用 /dev/urandom。

在 OpenBSD 上,Reader 會使用 getentropy(2)。

在其他的類 Unix 系統上,Reader 會讀取 /dev/urandom。

在 windows 系統上,Reader 會使用 CryptGenRandom API.

在 Wasm 上,Reader 會使用 Web Cryto API。

但是,獲得更好的質量意味著性能降低,因為它必須執行更多的操作并且不能使用預生成的序列。

性能

為了理解生成隨機數的兩種不同方式之間的折衷,我基于先前的兩個例子運行了一個基準測試。結果如下:

name    time/op
RandWithCrypto-8  272ns ± 3%
name    time/op
RandWithMath-8   22.8ns ± 4%

不出所料,crypto 包更慢一些。但是,如果你不用去處理安全的隨機數,那么 math 包就足夠了并且它將會給你提供最好的性能。

你也可以調整默認數字生成器,由于內部互斥鎖的存在,它是并發安全的。如果生成器并不在并發環境下使用,那么你就可以在不使用鎖的情況下創建你自己的生成器:

func main() {
   gRand := rand.New(rand.NewSource(1).(rand.Source64))
   for i := 0; i < 4; i++  {
      println(gRand.Intn(100))
   }
}

性能會更好:

name                  time/op
RandWithMathNoLock-8  10.7ns ± 4%

via:https://medium.com/a-journey-with-go/go-how-are-random-numbers-generated-e58ee8696999

作者:Vincent Blanchon[1]譯者:sh1luo[2]校對:lxbwolf[3]

本文由 GCTT[4] 原創編譯,Go 中文網[5] 榮譽推出

參考資料

[1]

Vincent Blanchon: https://medium.com/@blanchon.vincent

[2]

sh1luo: https://github.com/sh1luo

[3]

lxbwolf: https://github.com/lxbwolf

[4]

GCTT: https://github.com/studygolang/GCTT

[5]

Go 中文網: https://studygolang.com/

分享到:
標簽:隨機數 語言
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定