如何在 golang 中原子存储和加载接口?
How to atomic store & load an interface in golang?
我想写一些这样的代码:
var myValue interface{}
func GetMyValue() interface{} {
return atomic.Load(myValue)
}
func StoreMyValue(newValue interface{}) {
atomic.Store(myValue, newValue)
}
看来我可以使用 LoadUintptr(addr *uintptr) (val uintptr) 和 StoreUintptr(addr *uintptr, val uintptr) 在原子包中实现这个,但我不知道如何在 uintptr、unsafe.Pointer 和 [=20= 之间转换]接口{}.
如果我这样做:
var V interface{}
func F(v interface{}) {
p := unsafe.Pointer(&V)
atomic.StorePointer(&p, unsafe.Pointer(&v))
}
func main() {
V = 1
F(2)
fmt.Println(V)
}
V 永远是 1
你不能这样做。
您必须使用互斥锁来保护 store/load。
接口的内部表示不是由语言指定的,并且可能(是)大到由包 atomic 处理。
这是使用 atomic.StorePointer
和 atomic.LoadPointer
的方法(基于您的示例):
package main
import (
"fmt"
"sync/atomic"
"unsafe"
)
var addr unsafe.Pointer
func GetMyValue() *interface{} {
return (*interface{})(atomic.LoadPointer(&addr))
}
func StoreMyValue(newValue *interface{}) {
atomic.StorePointer(&addr, unsafe.Pointer(newValue))
}
func main() {
var i interface{}
i = 1
StoreMyValue(&i)
fmt.Println("before:", *GetMyValue())
i = 2
StoreMyValue(&i)
fmt.Println("after", *GetMyValue())
}
游乐场link
请注意,这不会使您的对象线程安全。只有指针是 stored/loaded 原子的。另外,我会避免使用 interface{}
并尽可能使用具体类型。
如果我没记错的话你想要 atomic Value。您可以使用它自动存储和获取值(签名是 interface{}
但您应该将相同的类型放入其中)。它在幕后做了一些不安全的指针,就像你想做的那样。
来自文档的示例:
var config Value // holds current server configuration
// Create initial config value and store into config.
config.Store(loadConfig())
go func() {
// Reload config every 10 seconds
// and update config value with the new version.
for {
time.Sleep(10 * time.Second)
config.Store(loadConfig())
}
}()
// Create worker goroutines that handle incoming requests
// using the latest config value.
for i := 0; i < 10; i++ {
go func() {
for r := range requests() {
c := config.Load()
// Handle request r using config c.
_, _ = r, c
}
}()
}
我想写一些这样的代码:
var myValue interface{}
func GetMyValue() interface{} {
return atomic.Load(myValue)
}
func StoreMyValue(newValue interface{}) {
atomic.Store(myValue, newValue)
}
看来我可以使用 LoadUintptr(addr *uintptr) (val uintptr) 和 StoreUintptr(addr *uintptr, val uintptr) 在原子包中实现这个,但我不知道如何在 uintptr、unsafe.Pointer 和 [=20= 之间转换]接口{}.
如果我这样做:
var V interface{}
func F(v interface{}) {
p := unsafe.Pointer(&V)
atomic.StorePointer(&p, unsafe.Pointer(&v))
}
func main() {
V = 1
F(2)
fmt.Println(V)
}
V 永远是 1
你不能这样做。
您必须使用互斥锁来保护 store/load。 接口的内部表示不是由语言指定的,并且可能(是)大到由包 atomic 处理。
这是使用 atomic.StorePointer
和 atomic.LoadPointer
的方法(基于您的示例):
package main
import (
"fmt"
"sync/atomic"
"unsafe"
)
var addr unsafe.Pointer
func GetMyValue() *interface{} {
return (*interface{})(atomic.LoadPointer(&addr))
}
func StoreMyValue(newValue *interface{}) {
atomic.StorePointer(&addr, unsafe.Pointer(newValue))
}
func main() {
var i interface{}
i = 1
StoreMyValue(&i)
fmt.Println("before:", *GetMyValue())
i = 2
StoreMyValue(&i)
fmt.Println("after", *GetMyValue())
}
游乐场link
请注意,这不会使您的对象线程安全。只有指针是 stored/loaded 原子的。另外,我会避免使用 interface{}
并尽可能使用具体类型。
如果我没记错的话你想要 atomic Value。您可以使用它自动存储和获取值(签名是 interface{}
但您应该将相同的类型放入其中)。它在幕后做了一些不安全的指针,就像你想做的那样。
来自文档的示例:
var config Value // holds current server configuration
// Create initial config value and store into config.
config.Store(loadConfig())
go func() {
// Reload config every 10 seconds
// and update config value with the new version.
for {
time.Sleep(10 * time.Second)
config.Store(loadConfig())
}
}()
// Create worker goroutines that handle incoming requests
// using the latest config value.
for i := 0; i < 10; i++ {
go func() {
for r := range requests() {
c := config.Load()
// Handle request r using config c.
_, _ = r, c
}
}()
}