美文网首页
GO原子操作(3)atomic.Value

GO原子操作(3)atomic.Value

作者: 尼桑麻 | 来源:发表于2019-03-28 12:58 被阅读0次

    为了扩大原子操作的适用范围,Go语言在1.4版本发布的时候向sync/atomic包中添加了一个新的类型Value。此类型的值相当于一个容器,可以被用来“原子地”存储和加载任意的值。
    atomic.Value类型是开箱即用的,我们声明一个该类型的变量(以下简称原子变量)之后就可以直接使用了。这个类型使用起来很简单,它只有两个指针方法——Store和Load。不过,虽然简单,但还是有一些值得注意的地方的。

    type ifaceWords struct {
        typ  unsafe.Pointer
        data unsafe.Pointer
    }
    

    ifaceWords结构体是实际存储我们的Value值的地方,可以看到,我们存储的实际是指向Value的type和data的指针.
    Store操作有两种行为模式:
    1.First Store : 当我们第一次调用Store的时候,Store函数会初始化typ指针(需要注意的是,每一个Value在第一次Store之后typ就被确定而不能更改了,否则会panic).
    2.后面的每次Store调用都是直接替换掉data指针

    Load函数检测typ的值,如果为nil或者正在进行首次调用Store则会返回nil.否则返回一个interface{}(实际存储的是ifaceWords值)

    使用规则

    第一条规则,不能用原子值存储nil
    我们不能把nil作为参数值传入原子值的Store方法,否则就会引发一个panic。
    这里要注意,如果有一个接口类型的变量,它的动态值是nil,但动态类型却不是nil,那么它的值就不等于nil。这样一个变量的值是可以被存入原子值的。

    第二条规则,我们向原子值存储的第一个值,决定了它今后能且只能存储哪一个类型的值
    第一次向一个原子值存储了一个string类型的值,那我在后面就只能用该原子值来存储字符串了。如果我又想用它存储结构体,那么在调用它的Store方法的时候就会引发一个panic。这个panic会告诉我,这次存储的值的类型与之前的不一致。
    Value值内部是依据被存储值的实际类型来做判断的,因此想通过接口类型的值,然后再存储这个接口的某个实现类型的值这样的方式是不可行的。

    使用建议

    1.不要把内部使用的原子值暴露给外界。比如,声明一个全局的原子变量并不是一个正确的做法。这个变量的访问权限最起码也应该是包级私有的。
    2.如果不得不让包外,或模块外的代码使用你的原子值,那么可以声明一个包级私有的原子变量,然后再通过一个或多个公开的函数,让外界间接地使用到它。注意,这种情况下不要把原子值传递到外界,不论是传递原子值本身还是它的指针值。
    3.如果通过某个函数可以向内部的原子值存储值的话,那么就应该在这个函数中先判断被存储值类型的合法性。若不合法,则应该直接返回对应的错误值,从而避免panic的发生。
    4.如果可能的话,我们可以把原子值封装到一个数据类型中,比如一个结构体类型。这样,我们既可以通过该类型的方法更加安全地存储值,又可以在该类型中包含可存储值的合法类型信息。

    相关文章

      网友评论

          本文标题:GO原子操作(3)atomic.Value

          本文链接:https://www.haomeiwen.com/subject/kkqqbqtx.html