首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Golang实例讲解,数字递增的线程安全性问题

Golang实例讲解,数字递增的线程安全性问题

原创
作者头像
一凡sir
修改2023-07-23 09:32:51
修改2023-07-23 09:32:51
9810
举报
文章被收录于专栏:技术成长技术成长

先上实例代码,后面再来详细讲解。

代码语言:go
复制
/**
 * 并发编程,数字递增的线程安全性问题
 */
package main

import (
   "sync"
   "time"
   "fmt"
   "sync/atomic"
)

var data1 int = 0
var data2 *int32
var wgInt sync.WaitGroup = sync.WaitGroup{}

func main() {
   t := int32(0)
   data2 = &t
   max := 100000
   wgInt.Add(max)
   fmt.Printf("data1 add num=%d\n", max)
   time1 := time.Now().UnixNano()
   for i := 0; i < max; i++ {
      go addData1()
   }
   wgInt.Wait()
   time2 := time.Now().UnixNano()
   fmt.Printf("data1=%d, time=%d ms\n", data1, (time2-time1)/1000000)

   wgInt.Add(max)
   fmt.Printf("data2 add num=%d\n", max)
   time3 := time.Now().UnixNano()
   for i := 0; i < max; i++ {
      go addData2()
   }
   wgInt.Wait()
   time4 := time.Now().UnixNano()
   fmt.Printf("data2=%d, time=%d ms\n", *data2, (time4-time3)/1000000)
}
// 简单的+1处理,线程不安全
func addData1() {
   data1++
   wgInt.Done()
}
// 原子性+1处理,线程安全
func addData2() {
   atomic.AddInt32(data2, 1)
   wgInt.Done()
}

实例中定义了两个数字data1, data2,一个是普通的int类型,一个是int32指针,data1用简单的++运算符递增,data2用atomic.AddInt32()方法递增

本地计算机是4核i5处理器,并发运行10w个协程,看到下面的运算结果,和大家预期的一样吗?

代码语言:shell
复制
data1 add num=100000

data1=98626, time=22 ms

data2 add num=100000

data2=100000, time=26 ms

为什么这么简单的++递增是不安全的呢?

这时,我们就需要深入理解计算机原理了。

++运算符实际上是三个操作,从内存读取data1,cpu更新data1=data1+1,写入data1到内存。

由于我们是多核并行运算的,那么从读取到写入整个过程中,就会出现不同的cpu内核读取到相同的数值,然后更新同样的数值写入到内存,这样就造成++数量比预期的少。

那么atomic.AddInt32()方法又是怎么保证数值递增的安全性呢?

这里就涉及到CAS( Compare and Swap )操作特定的一个复合指令cmpxchg,这个复合指令是现代CPU将上面的3条指令合成为一个指令,由CPU支持的一个复合指令,保证了操作的原子性。

并行运算时数据问题方面,CAS操作没有用互斥锁那么重,而使用的缓存锁的方式,在CPU高速缓存上对缓存行的一致性更新来保证数据更新的一致性

这里只是一个最简单的,单机同进程中,数字递增的并发处理,放大到分布式系统中,这种情况还会更加复杂,比如:如何安全的减少库存。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 先上实例代码,后面再来详细讲解。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档