
Go并发编程中的sync.Mutex锁及常见错误分析
本文剖析一段使用sync.Mutex锁和sync.WaitGroup进行并发编程的Go代码,这段代码试图通过1000个协程累加一个变量,但最终结果与预期(1000)不一致。让我们来分析代码并找出问题所在。
示例代码:
package mainimport ( "fmt" "sync" "time")func main() { haslockandwait()}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)}
代码预期结果是a最终值为1000,但实际运行结果往往小于1000。这是因为sync.Mutex的声明位置错误。
问题根源:var locker sync.Mutex这行代码在每个goroutine内部声明,这意味着每个goroutine都创建了一个独立的sync.Mutex实例。这些锁互不干扰,多个goroutine可以同时修改a,导致结果不准确。
解决方案:将sync.Mutex的声明移到for循环之外,使其成为全局锁,确保所有goroutine使用同一个锁来保护a变量。修改后的代码如下:
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函数,它提供原子操作,无需锁即可保证线程安全:
import "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)}
通过以上修改,可以确保并发累加操作的正确性,最终结果将为1000。 这强调了在Go并发编程中正确使用锁机制的重要性,错误的锁使用会导致数据竞争和不正确的程序行为。
以上就是Go并发编程中锁机制的常见错误:为什么1000个协程累加结果并非1000?的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1386196.html
微信扫一扫
支付宝扫一扫