go并发编程:sync.mutex失效及解决方案
本文分析一个Go并发编程案例,演示了sync.Mutex失效导致并发计数结果不准确的原因,并提供两种解决方案。 案例目标是使用1000个协程对一个变量进行累加,预期结果为1000,但实际结果却往往是随机值。
问题代码:
原代码错误地将sync.Mutex的声明放在for循环内部,导致每个协程都创建了一个独立的锁,无法保证对共享变量的原子操作。
package main import ( "fmt" "sync" "time" ) func haslockandwait() { var a = 0 var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go func(i int) { defer wg.Done() var locker sync.Mutex // 错误:每个协程都有独立的锁 locker.Lock() a++ locker.Unlock() }(i) } wg.Wait() fmt.Println("最终结果:", a) }
解决方案一:全局锁
将sync.Mutex的声明移到for循环外部,使其成为全局锁,确保所有协程使用同一个锁来保护共享变量。
package main import ( "fmt" "sync" "time" ) func hasLockAndWait() { var a = 0 var wg sync.WaitGroup var locker sync.Mutex // 正确:全局锁 for i := 0; i < 1000; i++ { wg.Add(1) go func(i int) { defer wg.Done() locker.Lock() a++ locker.Unlock() }(i) } wg.Wait() fmt.Println("最终结果:", a) }
解决方案二:使用atomic.AddInt64
使用sync/atomic包中的AddInt64函数进行原子操作,无需显式加锁,更高效。 这避免了锁的开销,尤其在高并发场景下更具优势。
package main import ( "fmt" "sync" "sync/atomic" ) func atomicAdd() { var a int64 = 0 var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() atomic.AddInt64(&a, 1) }() } wg.Wait() fmt.Println("最终结果:", a) }
通过以上两种方法,可以有效解决sync.Mutex失效的问题,确保并发计数结果的准确性。 选择哪种方法取决于具体场景和性能要求,atomic.AddInt64通常在高并发场景下更优。
以上就是Go并发编程中sync.Mutex失效了:为什么我的并发计数结果不准确?的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号