goland -sync/atomic原子操作小结

作者:Jeff的技术栈 时间:2024-04-26 17:20:08 

1.go已经提供了锁,为什么还需要atomic原子操作?

1.加锁代价比较高,耗时多,需要上下文切换。加锁解锁在代码层实现,而代码是运行在用户态空间中,对底层进行操作时需要从用户态空间切换到内核空间,再由内核操作底层资源。耗时多

2.原子操作在用户态可以完成,性能比互斥锁高。原子操作在cpu层面支持的,cpu可以直接操作底层资源

3.原子操作需求步骤简单,无需加锁解锁步骤

2.atomic原子操作为什么比mutex快?

1.原子操作快,是因为依赖于cpu指令,而不是依赖外部锁。不会额外的上下文切换
2.原子操作能够保证执行期间是连续且不会被中断(变量不会被其他修改,mutex可能存在被其他修改的情况)

3.CAS

CAS是cpu硬件同步原语,是Compare And Swap的缩写(比较并交换),原子操作中CAS,再sync/atomic包中,全部以ComparAndSwap开头的函数名都是CAS操作
   go中CAS操作,是借用CPU提供的原子性指令来实现。CAS操作修改共享变量时,不需要对共享变量加锁,而是通过类似乐观锁的方式进行检查,本质还是不断的占用CPU资源换取加锁带来的开销(如上下文切换时间开销)。

原子操作优势:
   可以在不形成临界区和创建互斥量的情况下完成并发安全的值替换操作。这可以大大的减少同步对程序性能的损耗。

原子操作劣势:
   在 * 作值被频繁的变更的情况下,CAS操作并不那么容易成功。因为需要对ild值进行匹配,只有匹配成功了才进行下一步的修改。

当前atmomic包有以下几种原子操作:
   Add,ComparAndSwap,Load,Store,Swap

4.互斥锁与原子操作区别

互斥锁目的:互斥锁是用来保护一段逻辑的,保证并发安全。(比如操作数据库保护)
原子操作目的:原子操作作用于一个变量的更新保护,保证并发安全(比如操作数据库不能原子操作)

mutex底层实现:mutex由操作系统的调度器实现
原子操作底层实现:由底层硬件指令直接提供支持,这些指令在执行过程中不允许中断,因此原子操作可以在无锁的情况下保证并发安全,性能随cpu的数量增多而线性扩展。

5.原子操作方法

5.1 atomic.AddInt32--增减

增减,操作方法的命名方式为AddXXX,保证对操作数进行原子的增减,支持的类型为int32、int64、uint32、uint64、uintptr,使用时以AddXXX就是对应的操作方法。

//加
func demo() {
var count int32 = 0
atomic.AddInt32(&count, 10)
fmt.Println(count) //10
}
//减
func demo() {
var count int32 = 0
atomic.AddInt32(&count, -10)
fmt.Println(count) //-10
}

锁和原子操作对比:

//Mutex锁
func demo1() {
sta := time.Now().Unix()
count := 0
mux := sync.Mutex{}
wg := sync.WaitGroup{}
for i := 0; i < 10000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 10000; j++ {
mux.Lock()
count++
mux.Unlock()
}
}()
}
wg.Wait()
fmt.Println(count) //100000000
fmt.Println(time.Now().Unix() - sta) //10秒
}

//atomic原子操作:快2倍不止
func demo2() {
sta := time.Now().Unix()
wg := sync.WaitGroup{}
var count int32 = 0
for i := 0; i < 10000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 10000; j++ {
atomic.AddInt32(&count, 1)
}
}()
}
wg.Wait()
fmt.Println(count) //100000000
fmt.Println(time.Now().Unix() - sta) //4秒
}

5.2 CAS-atomic.CompareAndSwapInt32--比较并替换

CompareAndSwap:比较并替换,类似乐观锁,先比较下old值与当前值是否一致,一致则把new的值替换
操作方法的命名方式为CompareAndSwapXXX

//true
func demo3() {
var count int32 = 0
boo := atomic.CompareAndSwapInt32(&count, 0, 100)
fmt.Println(count) //100
fmt.Println(boo)   //true
}

//false
func demo3() {
var count int32 = 0
boo := atomic.CompareAndSwapInt32(&count, 10, 100)
fmt.Println(count) //0
fmt.Println(boo) //false
}

5.3 atomic.StoreInt32--写操作

func demo3() {
var count int32 = 0
atomic.StoreInt32(&count, 666)
fmt.Println(count) //666
}

5.4 atomic.LoadInt32--读操作

func demo3() {
var count int32 = 0
atomic.StoreInt32(&count, 666)

val := atomic.LoadInt32(&count)
fmt.Println(val) //666
}

5.5 atomic.SwapInt32--直接交换

atomic.SwapInt32:直接交换,并返回交换前的值

func demo3() {
var count int32 = 0
old := atomic.SwapInt32(&count, 100)
fmt.Println(old)   //0
fmt.Println(count) //100
}

来源:https://www.cnblogs.com/guyouyin123/p/16565192.html

标签:goland,sync,atomic,原子
0
投稿

猜你喜欢

  • python 内置函数filter

    2023-01-07 21:53:37
  • vue中为何方法要写在methods的里面

    2024-05-10 14:19:24
  • python添加模块搜索路径方法

    2023-11-20 09:29:45
  • centos7环境下二进制安装包安装 mysql5.6的方法详解

    2024-01-26 23:37:33
  • vue使用Element el-upload 组件踩坑记

    2023-07-02 16:32:17
  • Python初学者必备的文件读写指南

    2023-03-16 11:44:15
  • PHP输出JSON格式数据方式

    2023-06-24 06:39:09
  • 简单介绍Python中的struct模块

    2023-09-22 16:27:01
  • 用Python编写分析Python程序性能的工具的教程

    2022-02-13 01:57:03
  • python调用支付宝支付接口流程

    2022-01-15 14:04:45
  • 小程序input数据双向绑定实现方法

    2023-07-15 13:09:54
  • git版本库介绍及本地创建的三种场景方式

    2023-07-11 11:22:18
  • 眼未动,心已动【碳酸饮料会】

    2009-09-01 19:32:00
  • python生成日历实例解析

    2023-05-16 12:47:31
  • thinkPHP学习笔记之安装配置篇

    2023-09-27 18:32:03
  • Python实现爬取网页中动态加载的数据

    2021-08-11 18:35:27
  • Python实例练习逆序输出字符串讲解

    2021-02-27 05:28:39
  • Python实现CAN报文转换工具教程

    2022-06-13 02:34:06
  • php下关于Cannot use a scalar value as an array的解决办法

    2023-10-29 22:29:23
  • 对python数据切割归并算法的实例讲解

    2023-02-10 05:32:08
  • asp之家 网络编程 m.aspxhome.com