一、随机数的概念
随机数是计算机中常使用的一种数值,它的产生具有不可预知性。随机数广泛应用于加密、模拟和统计学等领域。在Go语言中,随机数可以用math/rand包实现,利用各种方法使随机性进一步增强。
二、伪随机数生成器PRNG
在Go语言中,math/rand包提供了伪随机数生成器的函数,其中最常用的就是Intn(n)函数,可以产生一个[0,n)的伪随机整数。PRNG以种子值作为初始值,根据数学公式计算不同的随机数。由于具有确定性,所以称为伪随机数。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(rand.Intn(10))
}
运行上述代码,输出的结果是0~9的伪随机整数,由于使用了UnixNano()将纳秒级别的时间戳作为种子值,保证每次生成的随机数都不同。可以通过Seed()函数手动设置种子值。
三、真随机数生成器
相较于伪随机数,真随机数是真正的随机数,能够保证具有不可预知性。Go语言中提供了crypto/rand包,可以用于生成真随机数。
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
func main() {
n, err := rand.Int(rand.Reader, big.NewInt(100))
if err != nil {
fmt.Println("出错了")
}
fmt.Println(n)
}
运行上述代码,将产生一个范围在0~99的真随机整数。在生成真随机数时,必须指定特定的种子值,这里使用了cryptographic random generator实现安全产生真随机数。
四、使用多个goroutine
在并行计算中,需要产生多个随机数,每个goroutine都需要产生不同的随机数,可以使用rand.New()函数为每个goroutine创建一个独立种子的PRNG。
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 5; i++ {
fmt.Printf("Worker %d: %d\n", id, r.Intn(100))
time.Sleep(time.Millisecond * 100)
}
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
}
运行上述代码,会输出5个goroutine生成的随机数。这里每个goroutine都使用了一个独立的PRNG,因此产生的随机数的序列会不同。
五、结合时间的使用
在Go语言中,可以将时间结合到随机数产生中,可以根据时间戳计算出不同的种子值,并将其用作PRNG的初始值。
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
for i := 0; i < 5; i++ {
fmt.Println(rand.Intn(100))
time.Sleep(time.Millisecond * 100)
}
}
运行上述代码,每隔100毫秒将会产生一个0~99范围内的随机数。这里使用UnixNano()函数产生纳秒级别的时间戳,作为种子值,每次运行程序将产生不同的随机数序列。
六、总结
Go语言中提供了math/rand和crypto/rand包,分别用于产生伪随机数和真随机数。在多个goroutine环境下,可以为每个goroutine创建独立的PRNG来产生随机数。时间也可以结合随机数产生中,利用时间戳产生不同的种子值,进一步增强随机数生成的随机性。