Go math/rand 全局源并发使用有哪些误区
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) 返回一个可复现、但不保证并发安全的源。真正容易出错的地方,是看到“全局”二字就以为所有随机数对象都带锁。

| 调用对象 | 默认并发边界 | 工程选择 |
|---|---|---|
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))}
}

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 的调度顺序不固定,因此不能仅凭固定种子保证跨运行的调用顺序。
Go sort 排序结果不稳定是不是比较函数不满足约束
- 上一篇
- Go sort 排序结果不稳定是不是比较函数不满足约束
- 下一篇
- Go sync.Map LoadOrStore 怎样判断是否写入新值
-
- Golang · Go问答 | 21分钟前 |
- Go bytes.Cut 怎样同时取分隔符两侧的字符串
- 180浏览 收藏
-
- Golang · Go问答 | 22分钟前 | Go 锁复制 sync.Mutex 指针接收者 copylocks
- Go sync.Mutex 为什么不能复制
- 194浏览 收藏
-
- Golang · Go问答 | 24分钟前 | 标准库 · ip地址 · IPv6 Go ipv4 net.IP IsUnspecified
- Go net.IP.IsUnspecified 怎样区分 0.0.0.0、:: 和普通地址
- 143浏览 收藏
-
- Golang · Go问答 | 32分钟前 |
- Go sort 排序结果不稳定是不是比较函数不满足约束
- 353浏览 收藏
-
- Golang · Go问答 | 51分钟前 | https · Go问答 · tls Go 证书校验 ServerName SNI ClientHello
- Go TLS 客户端没有 SNI 会怎样
- 146浏览 收藏
-
- Golang · Go问答 | 56分钟前 |
- Go hmac.Equal 能否直接比较不同长度摘要
- 434浏览 收藏
-
- Golang · Go问答 | 1小时前 | Go 调试信息 Reader.Next debug/dwarf DWARF
- Go debug/dwarf.Reader.Next 怎样遍历 DWARF 调试条目
- 342浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 1022次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 1025次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1163次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1131次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 968次使用
-
- GScript 编写标准库示例详解
- 2022-12-30 369浏览
-
- 关于Golang标准库flag的全面讲解
- 2023-02-25 344浏览
-
- golang中随机数rand的使用
- 2023-01-27 494浏览
-
- Golang标准库unsafe源码解读
- 2022-12-29 464浏览
-
- 快速掌握Go语言HTTP标准库的实现方法
- 2022-12-30 327浏览

