当前位置:首页 > 文章列表 > Golang > Go问答 > Go math/rand 全局源并发使用有哪些误区

Go math/rand 全局源并发使用有哪些误区

来源:17golang原创 2026-11-14 16:18:04 0浏览 收藏

Go 的 math/rand 并发误区,通常不是“随机数会不会重复”,而是把不同层级的对象当成了同一种东西。结论先说清:rand.Intn、rand.Float64 这类顶层函数可以被多个 goroutine 并发调用;通过 rand.NewSource 创建的 Source,以及由它创建的 *rand.Rand,默认不能被多个 goroutine 直接共享。共享自建实例时要么给每个 goroutine 独占,要么在外层加同步。

官方参考:https://pkg.go.dev/math/rand

先分清顶层函数、Rand 与 Source

math/rand 可以拆成三层来理解:顶层函数使用包内部的默认源;rand.New(src) 把一个 Source 包装成 *Rand;rand.NewSource(seed) 返回一个可复现、但不保证并发安全的源。真正容易出错的地方,是看到“全局”二字就以为所有随机数对象都带锁。

Go math/rand 顶层函数、默认源、Rand 和 Source 的并发边界结构图
图1:并发边界结构说明图,区分顶层函数使用的默认源与自建 Rand、Source 实例。
调用对象默认并发边界工程选择
rand.Intn 等顶层函数可被多个 goroutine 并发使用简单的非安全随机任务优先直接调用
rand.NewSource 返回的 Source不支持直接并发共享独占,或由同步层保护
*rand.Rand方法不能与其他 Rand 方法并发调用每个 worker 一个,或封装互斥锁
crypto/rand面向安全随机数的另一套 API令牌、密钥等场景不要用 math/rand

全局函数为什么可以直接放进 goroutine

顶层函数和自建实例的并发语义不同。下面的代码只依赖包级入口,多个 goroutine 可以同时取一个范围内的整数;它没有把 rand.NewSource 返回值塞进共享结构,也没有暴露一个可变的 *rand.Rand 给所有 worker。

package main

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

func main() {
    var wg sync.WaitGroup
    for worker := 0; worker 

“可并发使用”不等于“每次结果都不同”,也不等于“结果不可预测”。math/rand 仍然是伪随机数包;如果业务需要密码学意义上的随机性,应改用 crypto/rand。另外,rand.Intn(n) 要求 n > 0,把外部配置直接传进去仍可能因为零值或负值触发 panic。

自建 Rand 要么独占,要么加锁

需要固定种子、独立随机序列或可复现实验时,通常会写 rand.New(rand.NewSource(seed))。这一步创建的是应用自己的状态,不会自动继承顶层函数的并发保证。最简单的做法是把它放在 worker 内部,让每个 worker 拥有自己的实例。

func worker(seed int64, count int) []int {
    // 每个 worker 独占 Source 和 Rand,避免多个 goroutine 读写同一状态。
    localRand := rand.New(rand.NewSource(seed))
    values := make([]int, 0, count)
    for i := 0; i 

如果业务必须共享一个序列,就把锁和 *rand.Rand 绑定在同一个小对象里,避免调用方绕过锁直接拿到内部指针。锁保护的是整个 Rand 方法调用,不是只保护种子字段。

type SafeRand struct {
    mu sync.Mutex
    r  *rand.Rand
}

func (s *SafeRand) Intn(n int) int {
    s.mu.Lock()
    defer s.mu.Unlock()
    // 锁覆盖完整的 Rand 调用,防止内部状态被并发修改。
    return s.r.Intn(n)
}

func newSafeRand(seed int64) *SafeRand {
    // 只在构造阶段创建实例,后续统一通过 SafeRand.Intn 访问。
    return &SafeRand{r: rand.New(rand.NewSource(seed))}
}
Go 自建 Rand 的独占实例与互斥锁共享结构说明图
图2:自建 Rand 的所有权结构示意图,对比 worker 独占与 SafeRand 统一加锁两种边界。

Seed、伪随机和参数边界不要混在一起

还有几个容易被并发问题掩盖的误区:

  • 不要为了“随机”在启动时反复调用顶层 Seed。当前文档已将包级 Seed 标记为 deprecated;如果目标是可复现序列,应显式创建带种子的独立 Rand,而不是修改包级默认状态。
  • 不要把伪随机当作安全随机。抽样、洗牌、模拟可以考虑 math/rand;验证码、重置令牌、密钥和签名材料应使用 crypto/rand。
  • 不要只看 race detector 的结果来决定设计。没有数据竞争,只能说明当前访问没有被检测到不安全并发,不能把“共享可变序列”自动变成合适的架构。先决定需要独立序列还是统一序列,再选独占或加锁。
  • 不要忽略边界参数。Intn(0) 和负数上界都会 panic;配置值、数组长度和业务过滤结果都应在调用前确认大于零。
速记:顶层函数可以并发用;自建 Source 和 Rand 默认按单 goroutine 设计。要复现就独占实例,要共享就用锁;要安全随机就换 crypto/rand。

相关问题

把 rand.Rand 放进单例后,所有方法都能并发调用吗?

不能。单例只是生命周期设计,不会自动增加同步;应让每个调用方独占实例,或通过一个不暴露内部指针的加锁包装访问。

顶层 rand.Intn 和 rand.New 的 Rand 有什么本质区别?

前者走包级默认源,并发语义由标准库保证;后者由调用方持有状态,种子和序列可控,但并发责任也回到了调用方。

固定种子是不是就能保证多个 goroutine 的结果顺序?

固定种子只能让同一个状态按同一访问顺序产生可复现序列。多个 goroutine 的调度顺序不固定,因此不能仅凭固定种子保证跨运行的调用顺序。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go sort 排序结果不稳定是不是比较函数不满足约束Go sort 排序结果不稳定是不是比较函数不满足约束
上一篇
Go sort 排序结果不稳定是不是比较函数不满足约束
Go sync.Map LoadOrStore 怎样判断是否写入新值
下一篇
Go sync.Map LoadOrStore 怎样判断是否写入新值
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    1022次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    1025次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1163次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1131次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    968次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码