惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
O
OpenAI News
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
Jina AI
Jina AI
D
Docker
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
雷峰网
雷峰网
V
V2EX
小众软件
小众软件
N
News | PayPal Newsroom
GbyAI
GbyAI
Recorded Future
Recorded Future
SecWiki News
SecWiki News
WordPress大学
WordPress大学
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
酷 壳 – CoolShell
酷 壳 – CoolShell
Security Latest
Security Latest
Google DeepMind News
Google DeepMind News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
Project Zero
Project Zero
Cyberwarzone
Cyberwarzone
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
U
Unit 42
The Last Watchdog
The Last Watchdog
V
Visual Studio Blog
C
Cisco Blogs
T
Tor Project blog
Google Online Security Blog
Google Online Security Blog
I
InfoQ
Attack and Defense Labs
Attack and Defense Labs
Y
Y Combinator Blog
博客园 - 聂微东
L
LangChain Blog
Blog — PlanetScale
Blog — PlanetScale
Apple Machine Learning Research
Apple Machine Learning Research
S
Schneier on Security
S
Securelist
博客园_首页
W
WeLiveSecurity
P
Privacy International News Feed
S
SegmentFault 最新的问题
博客园 - 【当耐特】
L
LINUX DO - 热门话题
Latest news
Latest news
大猫的无限游戏
大猫的无限游戏
M
MIT News - Artificial intelligence

Random Thoughts

LLM 训练与推理的基本理解 昨日的世界不再重来 Magic Brush - 画出你自己的产品宇宙 写在 AI Coding 奇点之后 尼泊尔布恩山小环线纪行 2025 投资组合年报 三十而笠 我的 8 年职业生涯回顾 我的颈椎病康复之旅 - 关于选择的故事 熊野古道中边路纪行 新加坡旅居三年再回首 高加索三国 - 阿塞拜疆行记 2024 投资组合年报 重新思考 Go:了解程序在线上是如何运行的 欧游散记 —— 环勃朗峰之旅 欧游散记 —— 特摩索斯古城 重新思考 Go:Channel 不是「消息队列」 重新思考 Go:Slice 只是「操作视图」 那一天,我决定踏出一步 True Story 少数价值 A Snapshot of Myself - 2021 RPC 漫谈: 连接问题 RPC 漫谈:序列化问题 RPC 漫谈: 限流问题 科学,技术与工程 Pond: Golang 通用对象池 Golang for-range 内部实现 Golang Interface 内部实现 真理的有限性 Meaningless or Meaningful 分布式文件系统的演化 从动物森友会聊主机游戏联机机制 创业公司的文化 伊朗见闻录 NodeJS 内存泄漏检测与定位 设计实现高性能本地内存缓存 Travel Map Linux I/O 栈浅析 SSD 背后的奥秘 什么是真正的编程能力 沉默与反沉默的理由 命令行里的设计艺术 自由意志下的选择 学习思维方式而非学习观点 从程序到人 —— 情头配对助手的前世今生 即刻多端实时通信实践 朝鲜 —— 小国寡民的主体思想实践 使用 Surge 提升多网络环境下的流畅开发体验 一份其实好吃的 LaTeX 入门餐 Kafka 的设计与实践思考 欧游散记 —— 民主专制下的德国 欧游散记 —— 维也纳 欧游散记 —— 西班牙 欧游散记 —— 德国国会大厦 社会矛盾讨论统一框架的一种可能性 欧游散记 —— 伪君子布拉格 Lemon : Koa 风格的 Python 异步 Web 框架 Golang : Make Programming Happy Again Podcast 闲言碎语 Kubernetes 中使用 API Gateway 替代 Ingress ElasticSearch 最佳实践 blog.joway.io Presentations
Golang rand 库锁竞争优化
Joway · 2020-12-17 · via Random Thoughts

背景

最近在实现一个随机负载均衡器的时候发现一个问题,在高并发的情况下,官方标准库 rand.Intn() 性能会急剧下降。翻了下实现以后才发现它内部居然是全局共享了同一个 globalRand 对象。

一段测试代码:

func BenchmarkGlobalRand(b *testing.B) {
   b.RunParallel(func(pb *testing.PB) {
      for pb.Next() {
         rand.Intn(100)
      }
   })
}

func BenchmarkCustomRand(b *testing.B) {
   b.RunParallel(func(pb *testing.PB) {
      rd := rand.New(rand.NewSource(time.Now().Unix()))
      for pb.Next() {
         rd.Intn(100)
      }
   })
}

输出:

BenchmarkGlobalRand
BenchmarkGlobalRand-8 18075486 66.1 ns/op
BenchmarkCustomRand
BenchmarkCustomRand-8 423686118 2.38 ns/op

解决思路

最理想对情况是可以在每个 goroutine 内创建一个私有的 rand.Rand 对象,从而实现真正的无锁。

但在很多其他场景下,我们并不能直接控制调用我们的 goroutine,又或者 goroutine 数量过多以至于无法承受这部分内存成本。

此时的一个思路是使用 sync.Pool 来为 rand.Source 创建一个池,当多线程并发读写时,优先从自己当前 P 中的 poolLocal 中获取,从而减少锁的竞争。同时由于只是用 pool 扩展了原生的 rngSource 对象,所以可以兼容其 rand.Rand 下的所有接口调用。

基于这个思路,实现了一个 fastrand 库放到了 github。

从 benchmark 中可以看到性能提升显著,在并发条件下,比原生全局 rand 快了大约 8 倍.

BenchmarkStandardRand
BenchmarkStandardRand-8                         60870416                19.1 ns/op             0 B/op          0 allocs/op
BenchmarkFastRand
BenchmarkFastRand-8                             100000000               10.7 ns/op             0 B/op          0 allocs/op
BenchmarkStandardRandWithConcurrent
BenchmarkStandardRandWithConcurrent-8           18058663                67.8 ns/op             0 B/op          0 allocs/op
BenchmarkFastRandWithConcurrent
BenchmarkFastRandWithConcurrent-8               132542940                8.79 ns/op            0 B/op          0 allocs/op