Loading... 在GoLang 中,我们可以通过 math/rand 包里的方法来生成一个伪随机数: ```Golang package main import ( "fmt" "math/rand" ) func main() { fmt.Println(rand.Int()) // => 134020434 } ``` 但如果你在本地,运行和我一样的代码,无论运行多少次,输出都是`一样的`。 # 随机种子 Golang的`math/rand`库会使用默认的随机种子——`1`来生成随机数。 我们知道,伪随机数,是使用一个确定性的算法计算出来的似乎是随机的数序,因此伪随机数实际上并不随机。如果在一开始输入这个算法的`创世参数`固定的话,算法生成的就是固定结果。 # 使用时间戳所谓随机种子 ```GoLang package main import "fmt" import "math/rand" import "time" func main() { rand.Seed(int64(time.Now().UnixNano())) fmt.Println(rand.Int()) } ``` 这样,每次运行时候的随机种子不一样,生成的随机数也就不一样了。 # 真随机数 > 真正的随机数是使用物理现象产生的:比如掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等等,这样的随机数发生器叫做物理性随机数发生器,它们的缺点是技术要求比较高。 通常情况下使用时间戳生成的随机数就可以满足要求。但是,伪随机数其实是有周期的。这就意味着在高安全要求下的身份验证、加密等情况使用伪随机数有风险。 所以一般企业对产品的加密秘钥的生成必须采用真随机数生成器,这样才能保证万无一失,杜绝了被破解的可能性。   那么Golang中使用真随机数的方法是使用`crypto/rand`包 ```Golang package main import ( "crypto/rand" "fmt" "math/big" ) func main() { // 生成 20 个 [0, 100) 范围的真随机数。 for i := 0; i < 20; i++ { result, _ := rand.Int(rand.Reader, big.NewInt(100)) fmt.Println(result) } } ``` 按照源文件,这些数据来自于每台机器: ```Golang // Package rand implements a cryptographically secure // pseudorandom number generator. package rand import "io" // Reader is a global, shared instance of a cryptographically // strong pseudo-random generator. // // On Linux, 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. ``` 以Linux为例,优先调用getrandom(2),其实就是/dev/random优先。与/dev/urandom两个文件,他们产生随机数的原理其实是差不多的,本质相同:都是利用当前系统的熵池来计算出固定一定数量的随机比特,然后将这些比特作为字节流返回。 > 熵池就是当前系统的环境噪音,熵指的是一个系统的混乱程度,系统噪音可以通过很多参数来评估,如内存的使用,文件的使用量,不同类型的进程数量等等。 简单来说,这个随机数的随机种子为`(进程数+内存占用长度+时间戳)`(只是举例解释,并非实际算法),而系统中存在多少线程完全就是随机的,无周期的。 但要注意,通过这种方式,要比math.rand`慢大约10倍`。 Last modification:March 8th, 2021 at 08:54 pm © 允许规范转载