zoukankan      html  css  js  c++  java
  • go语法:sync/atomaic原子操作

    参考:

     https://www.jianshu.com/p/6ca885ede2a8(sync/atomaic原子操作)

    协程并发问题

    在goroutine中访问外部的变量并不安全,我们先看看下面这个例子,我们执行一次计数,使用sync.WaitGroup包保证我们创建的1000个goroutine全部执行完毕后再输出n,运行程序看看结果如何:
    func no_atomic()  {
        var n int32
        var wg sync.WaitGroup
        for i := 0; i < 1000; i++ {
            wg.Add(1)
            go func() {
                n++
                wg.Done()
            }()
        }
        wg.Wait()
    
        fmt.Println(atomic.LoadInt32(&n)) // 978
    }

    电脑多核的情况下,不限制cpu执行上面代码,每次执行的结果不是1000,而是小于等于一千数值波动。为什么会出现这种情况呢?上面我们通过for循环里创建1000个goroutine,每个goroutine都将n加上1,加入有其中两个goroutine如下执行步骤:

    • goroutine1读取变量n 值为800
    • goroutine2读取变量n 值为800
    • goroutine1执行n+1,n变为801
    • goroutine2执行n+1,n变为801
    • 两次goroutine执行完毕
    • 结果n少加了一次1,所以最终的结果就比预期少1

    使用sync/atomic

    使用sync/atomic原子操作解决上述并发安全问题,代码如下:
    func _atomic()  {
        var n int32
        var wg sync.WaitGroup
        for i := 0; i < 1000; i++ {
            wg.Add(1)
            go func() {
                atomic.AddInt32(&n, 1)
                wg.Done()
            }()
        }
        wg.Wait()
    
        fmt.Println(atomic.LoadInt32(&n)) // 1000
    }
    使用 atomic.AddInt32进行加操作,最终输出预期的结果, 其实``atomic`包中的方法在执行完毕之前不会被其他的任务或者事件中断,该操作是并发安全,在向此地址写入或者读取值时原子性的操作,如果其他goroutine尝试读取或写入会被阻塞,知道此次原子操作完成。

    sync/atomic的原子操作

    主要有五大类:

    Load:该类方法主要负责从相应的内存地址中获取对应的值

    Store:该类主要负责将对应的值保存在相应的内存地址中

    Add:该类方法可以理解是Load和Store的结合,也就是先Load然后Add

    Swap:该类方法可以理解为先Load,在Store新值,然后返回旧值

    CompareAndSwap:该类方法可以这样理解:先比较旧数据和地址中保存数据的值,如果相同的话,执行Swap,把新的数值保存在地址中,返回true,如果不同,那么直接返回false

    常用方法:

    func AddT(addr *T, delta T)(new T) //计数
    func LoadT(addr *T) (val T) //获取值
    func StoreT(addr *T, val T)  //设置值
    func SwapT(addr *T, new T) (old T)  //设置值然后返回旧值
    func CompareAndSwapT(addr *T, old, new T) (swapped bool)

    具体

    //  下面是in32的
    func AddInt32(addr *int32, delta int32)(new int32)
    func LoadInt32(addr *int32) (val int32)
    func StoreInt32(addr *int32, val int32)
    func SwapInt32(addr *int32, new int32) (old int32)
    func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
    
    //  为(安全)指针类型提供以下四个原子函数:
    //  并没有AddPointer函数,因为go的指针不支持算术运算
    func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
    func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
    func SwapPointer(addr *unsafe.Pointer, new T) (old unsafe.Pointer)
    func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
     
     
  • 相关阅读:
    SQL 左外连接,右外连接,全连接,内连接
    CentOS 7.0默认使用的是firewall作为防火墙
    Python-WEB自动化-三种等待方式
    Python + Selenium的web自动化框架
    BS架构和CS架构的区别
    ERROR 1062 (23000): Duplicate entry '%-root' for key 'PRIMARY'
    CentOS 7镜像下载
    CentOS7各个版本镜像下载地址
    CentOS7的Minimal版本安装
    Python 文字转语音
  • 原文地址:https://www.cnblogs.com/tkzc2013/p/15217533.html
Copyright © 2011-2022 走看看