并发冲突案例与解决
并发冲突
package main
import "github.com/gin-gonic/gin"
func main() {
// 1、创建一个默认的路由引擎(包含日志Logger和恢复Recovery中间件)
r := gin.Default()
// 2、定义路由:当访问 /hello 时执行逻辑
count := 0 // TODO 存在并发安全问题
r.GET("/hello", func(c *gin.Context) { // 请求方式 + 请求路径 + 执行逻辑
count++
// 3、返回JSON响应,状态码200
c.JSON(200, gin.H{ // gin.H 底层是map[string]any
"message": "Hello Go-Learning",
"from": "Gin Framework",
"count": count,
})
})
// 4、启动服务,默认监听8080端口
r.Run()
}
count++底层分3步(非原子性)
- 读count值
- 加1
- 写回新值
协程并发访问count,先写入的值会被后写入的值覆盖。
例子:
Mac终端轻量压测工具ab并发100协程,发送10000请求访问http://localhost:8080/hello
ab -n 10000 -c 100 http://localhost:8080/hello
若无并发冲突,再次访问该接口时响应体中count应为10001
# 方式1:浏览器地址栏直接访问curl http://localhost:8080/hello
# 方式2 借助curl命令
curl http://localhost:8080/hello
浏览器

终端
![]()
该接口的访问计数器count数值出现混乱,不是从10001开始,发生了并发冲突。
解决
在 Go 语言中,处理这种简单的数值并发冲突,通常有以下两种方案
方案1:使用原子操作 (sync/atomic)
对于像计数器这种简单的整数加减,Go 提供了底层硬件支持的原子操作。它不需要复杂的上下文切换,性能是最高的。
- 1、将count定义为int64类型(原子操作库的要求)
- 2、使用 atomic.AddInt64(&count, 1) 实现自增
- 3、使用 atomic.LoadInt64 安全地读取当前数值
import (
"sync/atomic" // 引入原子操作包
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
var count int64 = 0 // 定义为 int64 类型的原子变量
r.GET("/hello", func(c *gin.Context) {
// 原子自增 1,该操作在 CPU 层面是不可分割的
newVal := atomic.AddInt64(&count, 1)
c.JSON(200, gin.H{
"message": "Hello Go-Learning",
"count": newVal, // 直接使用自增后的返回值
})
})
r.Run()
}
![]()
方案2:使用互斥锁 (sync/Mutex)
互斥锁(Mutex)通过“排队”机制确保同一时刻只有一个协程能访问临界区。虽然性能略逊于原子操作,但它更通用,可以保护更复杂的逻辑(比如同时修改多个变量)。
- 1、定义一个sync.Mutex实例。
- 2、读取和修改变量前调用Lock()。
- 3、操作完成后及时调用Unlock()。
package main
import (
"github.com/gin-gonic/gin"
"sync"
)
func main() {
r := gin.Default()
count := 0 // 全局计数器
var mu sync.Mutex // 1、声明一把互斥锁
r.GET("/hello", func(c *gin.Context) { // 请求方式 + 请求路径 + 执行逻辑
// 2、加锁,进入临界区
mu.Lock()
count++
currentCount := count // 3、将计算后的值暂存到局部变量中
// 4、离开临界区,立即解锁
mu.Unlock()
// 注意:尽量不要把 IO 操作(如 c.JSON 网络传输)包裹在锁内部,会严重拖慢并发性能
c.JSON(200, gin.H{
"message": "Hello Go-Learning",
"from": "Gin Framework",
"count": currentCount,
})
})
r.Run(":8080")
}
![]()

接口P99从87ms升至141ms,互斥锁带来一定性能损耗。

浙公网安备 33010602011771号