Golang中随机数的工作原理你真的懂了吗

Golang中随机数的工作原理你真的懂了吗 从 ret 包中我使用了以下代码:

func init() {
    rand.Seed(time.Now().UnixNano())
}

func RandomInt(n int) int {
    return rand.Intn(n)
}

main.go 中我这样调用:ret.RandomInt(number)。但出于某些原因,它似乎不受控制,因为在循环中它给了我太多重复的结果

for i := 1; i <=10; i++ { 
    y := ret.RandomInt(number)
    fmt.Println("-------", y)
}

运行结果可能如下所示:

------- 4
------- 16
------- 16
------- 16
------- 16
------- 16
------- 16
------- 16
------- 16
------- 3

或者

------- 22
------- 14
------- 14
------- 14
------- 14
------- 14
------- 14
------- 14
------- 14
------- 5

为什么会有这么多重复的数字?我希望能有更随机的表现。


更多关于Golang中随机数的工作原理你真的懂了吗的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

这绝对不应该这样工作。你能提供一个完整的可复现示例吗?

更多关于Golang中随机数的工作原理你真的懂了吗的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,GreyShatter。我无法再次复现该行为,看起来它工作正常。

该行为的原因是导入了错误的包。IDE使用了之前项目中的包导入。

// 代码示例
func main() {
    fmt.Println("hello world")
}

在Go语言中,rand包默认使用确定性伪随机数生成器,其行为由种子值决定。你遇到的问题是由于在并发环境下使用全局随机数生成器导致的竞态条件。

当多个goroutine同时调用rand.Intn()时,内部状态可能被并发修改,导致重复值出现。以下是修复方案:

// 创建独立的随机数生成器
var localRand = rand.New(rand.NewSource(time.Now().UnixNano()))

func RandomInt(n int) int {
    return localRand.Intn(n)
}

或者使用线程安全的方法:

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

var (
    rng = struct {
        sync.Mutex
        rand *rand.Rand
    }{
        rand: rand.New(rand.NewSource(time.Now().UnixNano())),
    }
)

func RandomInt(n int) int {
    rng.Lock()
    defer rng.Unlock()
    return rng.rand.Intn(n)
}

如果追求更好的随机性质量,可以使用crypto/rand包:

import "crypto/rand"

func CryptoRandomInt(n int) (int, error) {
    var b [8]byte
    _, err := rand.Read(b[:])
    if err != nil {
        return 0, err
    }
    
    randomUint := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 |
        uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 |
        uint64(b[6])<<48 | uint64(b[7])<<56
    
    return int(randomUint % uint64(n)), nil
}

第一个方案为每个调用创建独立的随机数生成器,第二个方案使用互斥锁保证线程安全,第三个方案使用密码学安全的随机数生成器。根据你的具体需求选择合适的方法。

回到顶部