Golang的原子包提供了功能func LoadUint32(addr *uint32) (val uint32).我查看了程序集实现:
TEXT ·LoadUint32(SB),NOSPLIT,$0-12
MOVQ addr+0(FP), AX
MOVL 0(AX), AX
MOVL AX, val+8(FP)
RET
Run Code Online (Sandbox Code Playgroud)
它基本上从内存地址加载值并返回它.我想知道我们是否有一个uint32指针(addr)x,调用atomic.LoadUint32(x)和使用它直接访问它有什么区别*x?
我想探讨一下当我们尝试复制变量时如何分配内存.我做了一些测试,这个让我困惑:
func testArrayAddress() {
var a [3]int
b := a
fmt.Printf("address of a %p and of b %p \n", &(a[0]), &(b[0]))
}
Run Code Online (Sandbox Code Playgroud)
输出是:
address of a 0xc8200126e0 and of b 0xc820012700
Run Code Online (Sandbox Code Playgroud)
但是,当我假设a和b并指向同一个数组时,第一个元素的起始地址应该相同?
这使我怀疑当我们执行声明时发生了什么b := a?原本我以为它只是分配一个内存块时,我们初始化变量数组a,并b := a使得b指向同一个内存位置,但随后它无法解释为什么第一个元素的地址是不一样的(这应该是相同的元素) .
我改变了第一行代码:
func testArrayAddress() {
var a = []int{1, 2, 3}
b := a
fmt.Printf("address of a's first element %p and of b %p \n", &(a[0]), &(b[0]))
}
Run Code Online (Sandbox Code Playgroud)
然后输出是:
address of a's first element 0xc8200126e0 …Run Code Online (Sandbox Code Playgroud) 我正在探索使用固定密钥同时访问地图的可能性,而没有锁定以提高性能.我以前用切片探索过类似的东西,似乎有效:
func TestConcurrentSlice(t *testing.T) {
fixed := []int{1, 2, 3}
wg := &sync.WaitGroup{}
for i := 0; i < len(fixed); i++ {
idx := i
wg.Add(1)
go func() {
defer wg.Done()
fixed[idx]++
}()
}
wg.Wait()
fmt.Printf("%v\n", fixed)
}
Run Code Online (Sandbox Code Playgroud)
上面的代码将通过-race测试.
这让我有信心用固定大小的地图(固定数量的键)实现同样的事情,因为我假设如果键的数量没有改变,那么下划线数组(在地图中)不需要扩展,所以它我们可以安全地访问不同的例行程序中的不同密钥(不同的内存位置).所以我写了这个测试:
type simpleStruct struct {
val int
}
func TestConcurrentAccessMap(t *testing.T) {
fixed := map[string]*simpleStruct{
"a": {0},
"b": {0},
}
wg := &sync.WaitGroup{}
// here I use array instead of iterating the map to avoid read access
keys := []string{"a", "b"} …Run Code Online (Sandbox Code Playgroud)