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

推荐订阅源

Google DeepMind News
Google DeepMind News
博客园 - 司徒正美
WordPress大学
WordPress大学
爱范儿
爱范儿
小众软件
小众软件
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
罗磊的独立博客
博客园_首页
V
V2EX
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
The Cloudflare Blog
MyScale Blog
MyScale Blog
IT之家
IT之家
H
Help Net Security
Blog — PlanetScale
Blog — PlanetScale
Microsoft Security Blog
Microsoft Security Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recent Announcements
Recent Announcements
F
Fortinet All Blogs
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
人人都是产品经理
人人都是产品经理

卡卡罗特

流行的Agent代码编辑器 eino实现Agent eino整合RAG eino整合Tools go整合向量数据库ChromaDB langchainjs langchain实现Agent ollama调用各大模型 spring-ai 自定义一个MCP openCV初体验 01-Bing每日一图接口 02-腾讯API高清QQ头像https调用接口 01-获取指定网站的所有的链接 context.Context是什么? SyncMap的使用 defer的使用 go字符串工具类 go生成UUID go正则表达式 最后代码 | 卡卡罗特 swagger文档 | 卡卡罗特 react脚手架开发 | 卡卡罗特 python的对象增强 | 卡卡罗特 langchain实现Agent | 卡卡罗特 03.python列表集合元组字典 | 卡卡罗特 python依赖打包 | 卡卡罗特 python的异步 | 卡卡罗特 python的生成器 | 卡卡罗特 eino整合Tools | 卡卡罗特
RWMutex读写锁
灯塔码铺-敲代码的卡卡罗特 · 2026-08-23 · via 卡卡罗特

Demo示例 ​

合理使用 RWMutex:

  • 写操作(initServices)使用 Lock()/Unlock()。
  • 读操作(getServices)使用 RLock()/RUnlock()。
  • 允许多个 goroutine 并发读,提高性能。

go

package main

import (
	"fmt"
	"sync"
	"time"
)

// 模拟服务依赖结构
type ServiceDeps struct {
	AppName string
	Version string
}

var (
	depsMu sync.RWMutex
	deps   *ServiceDeps // 全局共享数据,只写一次,多次读
)

// 安全读取 deps
func getServices() *ServiceDeps {
	depsMu.RLock()
	defer depsMu.RUnlock()
	return deps
}

// 初始化 deps(模拟“单线程写”)
func initServices() {
	depsMu.Lock()
	defer depsMu.Unlock()

	// Mock 数据
	deps = &ServiceDeps{
		AppName: "PriceMonitor",
		Version: "v1.0.0",
	}
	fmt.Println("✅ Services initialized!")
}

func main() {
	// 模拟应用启动:单线程初始化
	initServices()

	// 模拟多个并发请求(goroutine)同时读取
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			time.Sleep(time.Millisecond * 10) // 模拟处理延迟

			s := getServices()
			if s != nil {
				fmt.Printf("Worker %d: App=%s, Version=%s\n", id, s.AppName, s.Version)
			} else {
				fmt.Printf("Worker % d: ❌ services not ready!\n", id)
			}
		}(i)
	}

	wg.Wait()
	fmt.Println("🎉 All workers done.")
}

结果

text

✅ Services initialized!
Worker 0: App=PriceMonitor, Version=v1.0.0
Worker 3: App=PriceMonitor, Version=v1.0.0
Worker 1: App=PriceMonitor, Version=v1.0.0
Worker 4: App=PriceMonitor, Version=v1.0.0
Worker 2: App=PriceMonitor, Version=v1.0.0
🎉 All workers done.

疑问 ​

如果不加读锁会怎么样? ​

我之前以为,如果是读的话则可以多个请求读?写的话则会加锁,只有一个请求操作。那么感觉读锁没啥用,是否可以不显式的加读锁呢?好像貌似也没啥问题。

但其实上,加读锁是为了防止有写的情况。

  • 多个 goroutine 可以同时读(调用 RLock())✅
  • 写操作是独占的:只要有一个 goroutine 在写(Lock()),其他读和写都必须等待 ✅
  • 读和写不能同时进行:有读时不能写,有写时不能读 ✅

这正是“读写锁”(Read-Write Mutex)的核心语义。

注意,读锁和写锁是互斥的,所以多并发读的时候还是需要加上`RLock()/RUnlock()`的,避免并发修改

什么情况下可以不加锁?

  • 只有当满足以下所有条件时,才可以无锁读:
  • 变量在程序启动时一次性初始化(比如 init() 函数中)
  • 之后永远不再修改
  • 且初始化发生在 main 执行之前(或在 main 中单线程完成)