首页 > 编程知识 正文

golang interface,golang channel原理

时间:2023-05-06 13:18:23 阅读:172236 作者:2594

golang原子操作原文: http://if eve.com/go-concurrency-atomic /

1 .什么是原子操作。 已知原子操作是指在进行中不能被中断的操作。 也就是说,在对某个值进行原子操作的过程中,CPU决不执行对其他值的操作。 无论这些其他操作是否为原子操作,都会如此。 为了实现这种严密性,原子操作由一个独立的CPU指令代表并完成。 只有这样,才能保证同时环境下原子操作的绝对安全。

o语言提供的原子操作都是无创的。 它们由标准库代码包sync/atomic中的许多函数表示。 通过调用这些函数,可以对一些简单类型的值进行原子操作。

2.goalng中原子操作类型int32、int64、uint32、uint64、uintptr和unsafe.Pointer类型,共6个

3.golang有哪些原子操作? 即增加或减少,相比之下是交换、加载、保存和交换。

4.4.1进行增量或减量的原子操作(以下简称原子增量/减量操作)的函数名称均以“Add”为前缀,并命名相应的具体类型。 例如,实现针对uint32型的原子增减操作的函数的名称为AddUint32。 实际上,sync/atomic包中的所有函数的命名都遵循此规则。

4.2比较与交换部分读者可能熟悉比较与交换操作的英文标题——Compare And Swap,简称CAS。 在sync/atomic包中,这种原子操作由名称中以" CompareAndSwap "为前缀的几个函数表示。

以对int32型值的函数为例。 此函数的名称为CompareAndSwapInt32。 其声明如下

funccompareandswapint32 (addr * int 32,old,new int32 ) (swapped bool )可以看到compareandswapint 32函数接受三个参数。 第一个参数的值必须是指向操作值的指针值。 此值类型为*int32。 后两个参数的类型都是int32类型。 这些值必须表示操作值的旧值和新值。 CompareAndSwapInt32函数在调用参数addr指向的被操作值和参数old的值是否相等之后首先进行判断。 只有当这个判断得到肯定的结果时,函数才会用参数new表示的新值替换原始的旧值。 否则,后面的替换操作将被忽略。 这正是“比较交换”这个短语的由来。 CompareAndSwapInt32函数的结果swapped用于指示是否执行了值替换操作。

与上述锁相比,CAS操作存在明显差异。 假设操作的值始终保持不变,即等于旧值,在验证该假设的真实性后,将立即进行值的替换。 使用摇头丸是更慎重的做法。 首先,假设有一个并发操作,它更改操作的值,并使用锁定将相关操作放入临界区域以进行保护。 可以说使用摇头丸的做法变得悲观,CAS操作的做法变得更乐观。

CAS操作的优点是可以在不形成临界区域或创建互斥量的情况下完成并发安全的值替换操作。 这样可以大大减少同步导致的程序性能下降。 当然,CAS操作也有坏处。 在操作值频繁变更的情况下,CAS操作不会那么容易成功。 在某些情况下,可能必须利用for循环进行多次尝试。 例如以下所示。

varvalue int 32 func addvalue (delta int 32 ) for ) v :=valueifatomic.compareandswapint 32 ) value,v,v delta ) Breelta ) 这种方法与自旋锁定的自旋行为相似。 addValue函数将继续尝试更新原子的value值,直到此操作成功。 操作失败的原因是value的旧值始终不等于v的值。 如果value的值同时更改,这种情况很正常。

CAS操作不会用某个语句屏蔽某个Goroutine,但有可能会暂时停止进程的执行。 但是,这种停滞的时间大部分都是极短的。

请注意,如果希望同时安全地更新几种类型,更具体地说,上述六种类型的值,则必须始终优先使用CAS操作。

与此相比,用于原子的CAS操作的函数共有6个。 除了已经描述的CompareAndSwapInt32函数之外,还提供了CompareAndSwapPointer、compareandswappoint 32、CompareAndSwapUint64、CompareAndSwapUint64 这些参数声明列表与后者非常相似。 这三个参数的类型不同,但第二个和第三个参数的类型遵循与第一个参数的类型(即指针的类型)密切相关的规则。 例如,如果第一个参数的类型为*unsafe.Pointer,则最后两个参数的类型始终为unsafe.Pointer。 这也由这三个参数的含义决定。

p> 4.3 载入

在前面示例的for循环中,我们使用语句v := value为变量v赋值。但是,要注意,其中的读取value的值的操作并不是并发安全的。在该读取操作被进行的过程中,其它的对此值的读写操作是可以被同时进行的。它们并不会受到任何限制。

在第7章的第1节的最后,我们举过这样一个例子:在32位计算架构的计算机上写入一个64位的整数。如果在这个写操作未完成的时候有一个读操作被并发的进行了,那么这个读操作很可能会读取到一个只被修改了一半的数据。这种结果是相当糟糕的。

为了原子的读取某个值,sync/atomic代码包同样为我们提供了一系列的函数。这些函数的名称都以“Load”为前缀,意为载入。我们依然以针对int32类型值的那个函数为例。
我们下面利用LoadInt32函数对上一个示例稍作修改:制。

func addValue(delta int32) { for { v := atomic.LoadInt32(&value) if atomic.CompareAndSwapInt32(&value, v, (v + delta)) { break } }}

函数atomic.LoadInt32接受一个*int32类型的指针值,并会返回该指针值指向的那个值。在该示例中,我们使用调用表达式atomic.LoadInt32(&value)替换掉了标识符value。替换后,那条赋值语句的含义就变为:原子的读取变量value的值并把它赋给变量v。有了“原子的”这个形容词就意味着,在这里读取value的值的同时,当前计算机中的任何CPU都不会进行其它的针对此值的读或写操作。这样的约束是受到底层硬件的支持的。
注意,虽然我们在这里使用atomic.LoadInt32函数原子的载入value的值,但是其后面的CAS操作仍然是有必要的。因为,那条赋值语句和if语句并不会被原子的执行。在它们被执行期间,CPU仍然可能进行其它的针对value的值的读或写操作。也就是说,value的值仍然有可能被并发的改变。
与atomic.LoadInt32函数的功能类似的函数有atomic.LoadInt64、atomic.LoadPointer、atomic.LoadUint32、atomic.LoadUint64和atomic.LoadUintptr。

4.4 存储

与读取操作相对应的是写入操作。而sync/atomic包也提供了与原子的值载入函数相对应的原子的值存储函数。这些函数的名称均以“Store”为前缀。

4.5 交换

在sync/atomic代码包中还存在着一类函数。它们的功能与前文所讲的CAS操作和原子载入操作都有些类似。这样的功能可以被称为原子交换操作。这类函数的名称都以“Swap”为前缀。

转载于:https://www.cnblogs.com/waken-captain/p/10571877.html

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。