golang channel 和 mutex 及原子操作 用于并发控制的性能对比

场景:
对同个数加 10w 次,看耗费时间,这里没有用 benchmark 测试,在意的请略过。

以下是测试代码:

package main
import (
"fmt"
"sync"
"sync/atomic"
"testing"
"time"
)
func TestCount(t *testing.T) {
var cnt int
var wg sync.WaitGroup
numsWorkers := 100000
start := time.Now()
for i := 0; i < numsWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
cnt++
}()
}
wg.Wait()
fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}
func TestCountWithMutex(t *testing.T) {
var cnt int
var wg sync.WaitGroup
var mu sync.Mutex
numsWorkers := 100000
start := time.Now()
for i := 0; i < numsWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
cnt++
}()
}
wg.Wait()
fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}
func TestCountWithChannel(t *testing.T) {
var cnt int
var wg sync.WaitGroup
lock := make(chan struct{}, 1) // cap > 1, unsafe
numsWorkers := 100000
start := time.Now()
for i := 0; i < numsWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
lock <- struct{}{}
cnt++
<- lock
}()
}
wg.Wait()
fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}
func TestCountWithAtomic(t *testing.T) {
var cnt int64
var wg sync.WaitGroup
numsWorkers := 100000
start := time.Now()
for i := 0; i < numsWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&cnt, 1)
}()
}
wg.Wait()
fmt.Printf("Result, cnt: %d, time cost: %v\n", cnt, time.Now().Sub(start))
}

以下实测实结果:

$ go test -v
=== RUN TestCount
Result, cnt: 98431, time cost: 24.45ms
--- PASS: TestCount (0.02s)
=== RUN TestCountWithMutex
Result, cnt: 100000, time cost: 38.1108ms
--- PASS: TestCountWithMutex (0.04s)
=== RUN TestCountWithChannel
Result, cnt: 100000, time cost: 102.0231ms
--- PASS: TestCountWithChannel (0.10s)
=== RUN TestCountWithAtomic
Result, cnt: 100000, time cost: 26.5348ms
--- PASS: TestCountWithAtomic (0.03s)
PASS
ok go-test 0.235s

多次测试后,从性能对比看:原子操作 > mutex > channel,三者都可以保证并发的安全性,但在性能上,mutex 也没有那么差,并且比 channel 很很多,原子操作通过 cpu操作的原子性,实现无锁,但主要适合于一些单值的比较增减,对于操作序列来看,适合 mutex 及 channel,由于 golang 本身的互斥锁有一定自旋特性,对比单纯的公平锁还是有一定提升,所以个人认为 mutex 不一定比 channel 差。

posted on   进击的davis  阅读(95)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
历史上的今天:
2021-07-24 Dockerfile 多阶段构建镜像实践

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示