内容简介:sync/atomic包提供了底层的原子级内存操作,其执行过程不能被中断,这也就保证了同一时刻一个线程的执行不会被其他线程中断,也保证了多线程下数据操作的一致性。操作的数据类型共有六种:int32, int64, uint32, uint64, uintptr, unsafe.Pinter,每一种类型又提供了五种操作:Add增减, CompareAndSwap比较并交换, Swap交换, Load载入, Store存储。函数名以"操作+类型"组合而来。例如AddInt32/AddUint64/LoadInt
sync/atomic包提供了底层的原子级内存操作,其执行过程不能被中断,这也就保证了同一时刻一个线程的执行不会被其他线程中断,也保证了多线程下数据操作的一致性。
操作的数据类型共有六种:int32, int64, uint32, uint64, uintptr, unsafe.Pinter,每一种类型又提供了五种操作:Add增减, CompareAndSwap比较并交换, Swap交换, Load载入, Store存储。
函数名以"操作+类型"组合而来。例如AddInt32/AddUint64/LoadInt32/LoadUint64...
以Int32为例:
// AddInt32 atomically adds delta to *addr and returns the new value.
func AddInt32(addr *int32, delta int32) (new int32)
AddInt32可以实现对元素的原子增加或减少,函数会直接在传递的地址上进行修改操作。
addr需要修改的变量的地址,delta修改的差值[正或负数],返回new修改之后的新值。
var a int32 a += 10 atomic.AddInt32(&a, 10) fmt.Println(a == 20) // true //需要注意的是如果是uint32,unint64时,不能直接传负数,所以需要利用二进制补码机制 var b uint32 b += 20 atomic.AddUint32(&b, ^uint32(10-1)) // 等价于 b -= 10 // atomic.Adduint32(&b, ^uint32(N-1)) //N为需要减少的正整数值 fmt.Println(b == 10) // true
// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
函数会先判断参数addr指向的值与参数old是否相等,如果相等,则用参数new替换参数addr的值。最后返回swapped是否替换成功。
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var c int32
wg := sync.WaitGroup{}
//开启100个goroutine
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
tmp := atomic.LoadInt32(&c)
if !atomic.CompareAndSwapInt32(&c, tmp, tmp+1) {
fmt.Println("c 修改失败")
}
}()
}
wg.Wait()
//c的值有可能不等于100,频繁修改变量值情况下,CompareAndSwap操作有可能不成功。
fmt.Println("c : ", c)
}
偶尔输出:
//c 修改失败
//c : 99
多数情况下输出
//c : 100
// SwapInt32 atomically stores new into *addr and returns the previous *addr value.
func SwapInt32(addr *int32, new int32) (old int32)
Swap会直接执行赋值操作,并将原值作为返回值返回
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var e int32
wg2 := sync.WaitGroup{}
//开启10个goroutine
for i := 0; i < 10; i++ {
wg2.Add(1)
go func() {
defer wg2.Done()
tmp := atomic.LoadInt32(&e)
old := atomic.SwapInt32(&e, tmp + 1)
fmt.Println("e old : ", old)
}()
}
wg2.Wait()
fmt.Println("e : ", e)
}
// e old : 3
// e old : 1
// e old : 2
// e old : 4
// e old : 5
// e old : 6
// e old : 7
// e old : 8
// e old : 9
// e old : 0
// e : 10
// LoadInt32 atomically loads *addr.
func LoadInt32(addr *int32) (val int32)
Load函数参数为需要读取的变量地址,返回值为读取的值
Load和Store操作对应与变量的原子性读写,许多变量的读写无法在一个时钟周期内完成,而此时执行可能会被调度到其他线程,无法保证并发安全。Load只保证读取的不是正在写入的值,Store只保证写入是原子操作。所以在使用的时候要注意。
// StoreInt32 atomically stores val into *addr.
func StoreInt32(addr *int32, val int32)
Store函数参数为需要存储的变量地址及需要写入的值,存储某个值时,任何CPU都不会对该值进行读或写操作,存储操作总会成功,它不关心旧值是什么,与CompareAndSwap不同
var d int32
fmt.Println("d : ", d)
atomic.StoreInt32(&d, 666)
fmt.Println("d : ", d)
以上所述就是小编给大家介绍的《Go原子操作 sync/atomic》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- JAVA之原子操作原理
- Go36-29,30-原子操作
- go redigo执行lua脚本 实现原子操作
- CAS原子操作以及其在Java中的应用
- JavaBaas 2.0.0 正式版发布:增加数据原子操作
- 新姿势!Redis中调用Lua脚本以实现原子性操作
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
《生活大爆炸》之科学揭秘
乔治·毕姆 / 韩准、徐漪、江业华、叶夜 / 世界图书出版公司 / 2012-12 / 49.00元
《 之科学揭秘:GEEK探索频道》对流行美剧《生活大爆炸》进行“深度解密”,重点在解读剧中涉及的流行文化及科学元素。正如我们所知,《生活大爆炸》是一部“技术含量很高”的肥皂剧。不光是普通观众,科学家也爱《生活大爆炸》。《 之科学揭秘:GEEK探索频道》中,科学家详尽为你解释了电视剧中出现的科学道理和典故。包括谢尔顿的高深弦理论、霍华德的花生过敏是怎么回事、如果你和谢尔顿的妈妈有同样的信仰该如何看待......一起来看看 《《生活大爆炸》之科学揭秘》 这本书的介绍吧!