go隨機數


math/rand

math/rand實現了偽隨機數算法,和其它的編程語言類似,操作邏輯都是先設置隨機數種子,然后再獲取隨機數序列。這樣每次生成的隨機數序列都是不一樣的。

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < 10; i++ {
		// 生成0~99的隨機數
		fmt.Println(rand.Intn(100))
	}
}

並且go還保證了上述的代碼生成隨機數是線程安全的,因為里面的操作加鎖了,但可能有很少的場景強調效率,也可以自己創建一個偽隨機源,這樣就不會加鎖了。

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 10; i++ {
		// 生成0~99的隨機數
		fmt.Println(r.Intn(100))
	}
}

crypto/rand

上面math/rand包生成的隨機數是偽隨機的,可以根據上一個隨機數的值計算出下一個,只是在總體的分布上是均勻的,來模擬隨機。
但有些場景需要密碼學安全的隨機數,也就是無法預測的隨機數,所以go語言提供了crypto/rand包,里面提供了真隨機數產生接口,滿足密碼學安全的需求。

package main

import (
	"crypto/rand"
	"fmt"
)

func main() {
	b := make([]byte, 10)
    // Reader is a global, shared instance of a cryptographically
    // secure random number generator.
    //
    // On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise.
    // On OpenBSD, Reader uses getentropy(2).
    // On other Unix-like systems, Reader reads from /dev/urandom.
    // On Windows systems, Reader uses the CryptGenRandom API.
    // On Wasm, Reader uses the Web Crypto API.
	rand.Read(b)
	fmt.Println(b)
}

linux真隨機數

為了獲得真正意義上的隨機數,需要一個外部的噪聲源。Linux內核找到了一個完美的噪聲源產生者--就是使用計算機的人。
內核根據非確定性的設備事件維護着一個熵池,池中的數據是完全隨機的。當有新的設備事件到來,內核會估計新加入的數據的隨機性,當我們從熵池中取出數據時,內核會減少熵的估計值。
/dev/random/dev/urandom這兩個特殊設備都是字符型設備。我們可以在用戶空間通過read系統調用讀這兩個設備文件以此獲取隨機數。這兩個設備文件的區別在於:如果內核熵池的估計值為0時,/dev/random將被阻塞,而/dev/urandom不會有這個限制。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM