当前位置:首页 > 文章列表 > Golang > Go问答 > Go RWMutex 读锁很多时写操作如何获得机会

Go RWMutex 读锁很多时写操作如何获得机会

来源:17golang原创 2026-09-09 10:51:21 0浏览 收藏

读多写少的配置、路由表或本地缓存经常会用到 sync.RWMutex。读锁很多时,写操作并不是靠“抢跑”获得机会:已经拿到 RLock 的读者先完成,写者调用 Lock 后,后续新的 RLock 会被挡住,等现有读者退出后让写者进入。

所以 Go 的 RWMutex 具备防止写者长期饥饿的排队语义,但不是严格的读写 FIFO 调度器;写者能获得机会,不等于每个请求都有固定顺序。
要点速览
  • 写者等待期间,新的读者不能继续加入当前读者组。
  • 读方法用 RLock/RUnlock,更新方法用 Lock/Unlock,锁不能复制。
  • 不要在持有读锁时再升级写锁;慢计算应放在锁外,锁内只做快照读写。

把读多写少配置做成一个小项目

先做一个极小的配置存储:HTTP 请求频繁读取 timeout,后台任务偶尔把它改成新值。关键不是把所有方法都加锁,而是让共享 map 的每次访问都落在正确的锁范围内。

package main

import (
	"fmt"
	"sync"
)

// ConfigStore 保存可被多个 goroutine 读取的配置快照。
type ConfigStore struct {
	mu   sync.RWMutex
	data map[string]string
}

// Get 只读取共享 map,因此使用读锁。
func (s *ConfigStore) Get(key string) (string, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	value, ok := s.data[key]
	return value, ok
}

// Set 修改共享 map,必须独占整个更新区间。
func (s *ConfigStore) Set(key, value string) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.data[key] = value
}

func main() {
	store := &ConfigStore{data: map[string]string{"timeout": "800ms"}}
	store.Set("timeout", "1s")
	value, ok := store.Get("timeout")
	fmt.Println(value, ok) // 这里会读到一次完整的配置值
}

这里的 defer 放在成功加锁之后,能保证每个出口都解锁。RWMutex 本身不要按值复制;把它作为结构体字段,并通过指针接收者调用,是更稳妥的组织方式。

调用可并发对象关键边界
RLock多个读者只读共享状态,结束后必须 RUnlock
Lock单个写者等待读者退出,更新期间排斥读写
读转写不支持升级先释放读锁再重新申请写锁,期间状态可能变化

写者等待时读锁为什么会让出通道

假设读者 R1、R2 已经拿到读锁,此时写者 W 调用 Lock。W 不能打断 R1、R2,但它一旦进入等待,之后到达的 R3、R4 不能再通过 RLock 加入。R1、R2 依次 RUnlock 后,W 获得独占锁并完成更新,W 释放后,排队的读者才继续。

Go sync.RWMutex 中已有读者、等待写者与后续读者之间的静态边界关系
图1:把已持有读锁、等待写锁和后续读者分在不同边界中,理解写者等待时新读者为何不能插队。

这正是“写者如何获得机会”的答案。它不是承诺 W 一定紧接着某个读者执行,也不是按到达时间给所有 goroutine 排号,而是先阻断新的读者,避免读者流持续增长把写者压在队列末尾。

防止把写者机会误解成严格公平

RWMutex 的公平性应理解为边界规则,而不是调度承诺:

  • 已经持有的读者不会被强行踢出;读临界区越长,写者等待越久。
  • 写者一旦等待,新的读者会阻塞,但唤醒顺序仍不应被业务代码当成稳定的 FIFO。
  • 读锁不能递归依赖。一个 goroutine 持有读锁后再等待写者完成,可能形成自我等待。

因此,读操作里不要做网络请求、磁盘扫描或长时间计算。先在锁内复制必要字段,再在锁外慢慢处理,通常更容易让写者及时穿过临界区。

Go ConfigStore 使用 sync.RWMutex 保护配置快照并将慢处理移到锁外的静态结构
图2:查看配置快照、读锁、写锁和锁外处理的静态关系,区分共享状态保护与慢操作边界。

一个实用的排查清单

遇到“写操作偶尔很慢”时,先检查四件事:读者是否把外部调用放在 RLock 内;是否存在忘记 RUnlock 的分支;写者是否在锁内做了序列化或 I/O;是否有人试图先读后写而没有释放读锁。若写入频率已经很高,或者读写内容可以通过消息传递串行化,通道或不可变快照也可能比 RWMutex 更适合。

常见问题

读锁很多时,新的读请求会永远失败吗?

不会。它们通常只是等待写者完成;写者释放后,排队的读者可以继续获取读锁。

能否在 RLock 后直接调用 Lock?

不能把它当作升级操作。先调用 RUnlock,再调用 Lock,但这两个动作之间可能有其他写入。

RWMutex 是否比 Mutex 一定快?

不一定。只有读并发明显、读临界区短且写入相对少时,多个读者并行才可能抵消额外管理成本,应结合实际竞争情况评估。

官方文档对 RWMutex 的描述可以作为最终判断依据:它允许任意数量的读者或一个写者;写者等待时,新的读锁会阻塞,直到写者获得并释放锁。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go 1.27 原生 uuid 包如何改变项目依赖选择Go 1.27 原生 uuid 包如何改变项目依赖选择
上一篇
Go 1.27 原生 uuid 包如何改变项目依赖选择
PHP match 表达式没有匹配分支时如何设计默认结果
下一篇
PHP match 表达式没有匹配分支时如何设计默认结果
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之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推荐
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    41次使用
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    193次使用
  • C-Eval中文评测基准:大语言模型多学科能力评估指南
    C-Eval
    深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
    129次使用
  • AI Prompt Library:免费AI提示词库,助力ChatGPT高效创作与营销
    AI Prompt Library
    探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
    60次使用
  • Generrated:DALL·E 2/3 AI绘画提示词灵感库与图像对比平台
    Generrated
    Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
    42次使用