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 差。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2021-07-24 Dockerfile 多阶段构建镜像实践