Golang:什么是原子读取用于?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang:什么是原子读取用于?相关的知识,希望对你有一定的参考价值。
在这里,我们有一个由Go by Example
提供的案例来解释原子包。
https://gobyexample.com/atomic-counters
package main
import "fmt"
import "time"
import "sync/atomic"
func main() {
var ops uint64
for i := 0; i < 50; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
time.Sleep(time.Millisecond)
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops) // Can I replace it?
fmt.Println("ops:", opsFinal)
}
对于atomic.AddUnit64
来说,它很容易理解。
问题1
关于read
操作,为什么有必要使用atomic.LoadUnit
,而不是直接读这个计数器?
问题2
我可以用以下几行替换最后两行吗?
之前
opsFinal := atomic.LoadUint64(&ops) // Can I replace it?
fmt.Println("ops:", opsFinal)
后
opsFinal := ops
fmt.Println("ops:", opsFinal)
问题3
我们担心这种情况吗?
- CPU从内存加载数据
- CPU操纵数据
- 将数据写回内存。即使这一步很快,但仍需要时间。
当CPU执行step3时,另一个goroutine可能会从内存中读取不完整和脏的数据。那么使用atomic.LoadUint64
可以避免这种问题吗?
参考
答案
有必要使用atomic.LoadUint64
,因为不能保证:=
操作符进行原子读取。
举个例子,考虑一个atomic.AddUint64
实现如下的理论案例:
- 锁定。
- 读低32位。
- 读高32位。
- 将数字添加到低32位。
- 将第一个操作的执行添加到高32位。
- 写低32位。
- 写高32位。
- 解锁。
如果您不使用atomic.LoadUint64
,您可能正在阅读第6步和第7步之间的中间结果。
在某些平台上(例如,没有本机支持64位整数运算的旧ARM处理器),它可以很好地以上述方式实现。
这同样适用于其他大小的整数/指针。确切的行为将取决于atomic
包的实现以及运行该程序的CPU /内存体系结构。
以上是关于Golang:什么是原子读取用于?的主要内容,如果未能解决你的问题,请参考以下文章
golang goroutine例子[golang并发代码片段]