You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言实现写时阻塞读、读操作互不阻塞的方案问询

解决方案:用读写锁实现读并发、写阻塞读的并发控制

你当前的代码问题出在使用了sync.Mutex互斥锁——它不管是读操作还是写操作,每次都只允许一个goroutine持有锁,导致多个reader之间也会互相阻塞,完全不符合你"reader之间互不阻塞,仅writer修改时阻塞读"的需求。

Go标准库中的sync.RWMutex正好适配这个场景:

  • 读锁(RLock()/RUnlock()):允许多个reader同时持有读锁,互相不会阻塞
  • 写锁(Lock()/Unlock()):当writer获取写锁时,会等待所有正在进行的读操作完成,同时阻塞后续的读和写请求,直到写锁释放,确保数据修改的原子性

下面是修改后的完整代码,同时修复了原代码中的一些小问题(比如time.Seconds拼写错误、goroutine匿名函数写法、main函数提前退出等):

package main

import (
	"sync"
	"time"
)

var data []int

// 模拟读数据的业务逻辑
func read_from_data(d []int) {
	// 这里可以添加你的读操作,比如打印数据、处理切片等
}

// 模拟生成新数据的逻辑
func new_data() []int {
	return []int{time.Now().Second(), time.Now().Minute()}
}

func main() {
	m := sync.RWMutex{} // 将互斥锁替换为读写锁

	// 启动10个reader goroutine
	for i := 0; i < 10; i++ {
		go func() {
			for {
				m.RLock() // 获取读锁,多个reader可同时持有
				myData := data // 读取共享数据
				m.RUnlock() // 尽早释放读锁,避免不必要地阻塞写操作

				// 耗时的读业务逻辑放在锁外执行
				read_from_data(myData)
				time.Sleep(100 * time.Millisecond) // 避免reader过度占用CPU
			}
		}()
	}

	// 启动writer goroutine
	go func() {
		for {
			newData := new_data()
			m.Lock() // 获取写锁,此时所有新的读请求会被阻塞
			data = newData // 原子性地修改共享数据
			m.Unlock() // 释放写锁,读操作恢复并发

			time.Sleep(1 * time.Second) // 写操作间隔1秒
		}
	}()

	// 阻塞main goroutine,避免程序提前退出导致所有goroutine终止
	select {}
}

几个关键注意点:

  • 读锁的释放时机:尽量在读取完共享数据后立刻释放读锁,不要带着读锁执行耗时的业务逻辑(比如read_from_data),这样能最大程度减少对写操作的阻塞。
  • 写锁的排他性:写锁会完全阻塞所有读写操作,所以写操作的逻辑要尽量精简,减少持有写锁的时间。
  • main函数的阻塞:原代码中main函数启动goroutine后会直接退出,导致所有goroutine被强制终止,所以用select {}让main一直运行。

内容的提问来源于stack exchange,提问作者arash kordi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:02:06