Golang atomic.LoadInt64() 函数及其示例
在 Golang 的并发编程中,为了避免竞态条件和锁的开销,我们经常会用到原子操作。而 atomic.LoadInt64()
函数则是其中的一种,它可以原子地获取一个 int64
类型的值。
函数定义
atomic.LoadInt64()
函数的定义如下:
func LoadInt64(addr *int64) (val int64)
其中,addr
表示要获取的 int64
类型地址。函数返回值是地址 addr
的 int64
类型值。
函数示例
示例 1:正常使用
下面是一个正常使用 atomic.LoadInt64()
函数的示例:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var num int64 = 0
var wg sync.WaitGroup
// 开启 100 个协程,每个协程将 num 的值加 1
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
atomic.AddInt64(&num, 1)
wg.Done()
}()
}
wg.Wait()
// 获取 num 的值
val := atomic.LoadInt64(&num)
fmt.Println(val) // 输出 100
}
这里将 num 的初始值设为了 0。然后开启了 100 个协程,每个协程将 num 的值加 1。最后使用 atomic.LoadInt64()
函数原子地获取了 num 的值,并输出。
示例 2:与普通变量获取的差别
我们也可以结合一个不使用原子操作的版本,来看看使用原子操作与不使用原子操作的区别:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func normalAdd(wg *sync.WaitGroup, num *int64) {
*num = *num + 1
wg.Done()
}
func main() {
var num int64 = 0
var wg1 sync.WaitGroup
// 开启 100 个协程,每个协程使用普通变量实现 num 的加 1
for i := 0; i < 100; i++ {
wg1.Add(1)
go normalAdd(&wg1, &num)
}
wg1.Wait()
fmt.Println(num) // 输出 100
var wg2 sync.WaitGroup
// 开启 100 个协程,每个协程使用原子操作实现 num 的加 1
for i := 0; i < 100; i++ {
wg2.Add(1)
go func() {
atomic.AddInt64(&num, 1)
wg2.Done()
}()
}
wg2.Wait()
// 获取 num 的值
val := atomic.LoadInt64(&num)
fmt.Println(val) // 输出 200
}
这里将 normalAdd()
函数作为不使用原子操作的版本,与示例 1 相对应。
在示例中,我们先使用 normalAdd()
开启了 100 个协程,每个协程使用普通变量实现 num 的加 1。然后用 atomic.AddInt64()
再开启 100 个协程,使用原子操作实现 num 的加 1。最后使用 atomic.LoadInt64()
函数原子地获取了 num 的值。
运行示例代码,可以发现使用原子操作和不使用原子操作获取 num 的差别,前者数量为 200,后者数量为 100。
结论
atomic.LoadInt64()
函数是 Golang 并发编程中的一个重要工具,通过它可以原子地获取 int64
类型的值,避免竞态条件和锁的开销。当然,在实现并发程序时,我们还要结合实际情况选择使用合适的原子操作。