Go 更新全局范围变量值

Go 更新全局范围变量值,go,Go,我有一个json文件,其中有数千条记录作为键值对,我通过将其解组为接口来读取这些记录 var devices map[string]interface{} //globalscope in app jsonFast:= jsoniter.ConfigFastest _, b, _, _ := runtime.Caller(0) dir := filepath.Dir(b) jsonFile, _ := ioutil.ReadFile(dir + "/devices.json") _ = jso

我有一个json文件,其中有数千条记录作为键值对,我通过将其解组为接口来读取这些记录

var devices map[string]interface{} //globalscope in app
jsonFast:= jsoniter.ConfigFastest
_, b, _, _ := runtime.Caller(0)
dir := filepath.Dir(b)

jsonFile, _ := ioutil.ReadFile(dir + "/devices.json")
_ = jsonFast.Unmarshal(jsonFile, &devices)
在应用程序运行过程中,多个goroutine可在高负载下访问此功能

现在,由于此文件每5分钟更新一次,因此在不重新启动应用程序的情况下,我希望使此地图界面无效
设备
,以便从文件加载新数据

在node.js中,我曾经使用
delete require.cache[require.resolve(“filename”)]
,但不确定如何在go中实现这一点

我曾尝试在SetInterval func(节点版本的端口)中使用互斥锁,每5分钟读取一次文件,但出现以下错误:


goroutine 871895[IO wait]:
这似乎意味着goroutine正在等待解锁以从全局变量读取

代码:


我应该采取什么方法来实现这一点?或者有没有办法从文件中读取/更新,而不是使用映射接口来避免争用条件和IO锁定?

我认为问题与这样一个事实有关,即当您试图用新数据覆盖映射时,仍然有goroutines从映射中读取。我建议您使用
sync.RWMutex
来保护它,并按如下方式操作:

type GlobalState struct {
    data map[string]interface{}
    sync.RWMutex
}

func (gs *GlobalState) Get(key string) interface{} {
    gs.RLock()
    defer gs.RUnlock()
    return gs.data[key]
}

func (gs *GlobalState) Refresh() {
    jsonFile, _ := ioutil.ReadFile(dir + "/devices.json")
    gs.Lock()
    defer gs.Unlock()
    _ = jsonFast.Unmarshal(jsonFile, &gs.data)
}

var devices GlobalState

func main() {
    t := time.NewTicker(5 * 60 * time.Second)
    for ; true; <-t.C {
         devices.Refresh()
    }
}
类型GlobalState结构{
数据映射[字符串]接口{}
sync.RWMutex
}
func(gs*GlobalState)Get(键字符串)接口{}{
gs.RLock()
延迟gs.RUnlock()
返回gs.数据[键]
}
func(gs*全局状态)刷新(){
jsonFile,Util:=ioutil.ReadFile(dir+“/devices.json”)
gs.Lock()
延迟gs.Unlock()
_=jsonFast.Unmarshal(jsonFile,&gs.data)
}
var设备全球状态
func main(){
t:=时间.新调克(5*60*时间.秒)

for;true;
goroutine 871895[IO等待]
不是错误,这是goroutine的状态。错误应该在转储的开始。请包括实际错误。确保地图访问稍微安全的一种方法是将整个地图包装在一个
sync.RWMutex
中,但这需要在读/写之前锁定整个地图。如果您的JSON具有已知的结构的确,您很可能应该将其解组到结构中,然后将结构的每个部分包装到互斥锁中。@johnos,代码当前已经锁定了映射。这样的细粒度方法在替换整个结构时能实现什么?当前代码的问题是,除非所有读取都使用相同的互斥锁完成,否则它是racy.B让我们先看看这个错误。使用jsoniter可能是明智的,但为什么要在ioutil.ReadFile之后使用它呢?过早的优化?我会尝试一下,我希望这不会锁定任何goroutine,并且会在内存和CPU上提高效率?在我添加
time.NewTicker
code before/after
log.Fatal(server.ListenAndServe()之后,应用程序不会在端口上侦听)
,这是预期的还是我做错了什么?我还可以将
键入GlobalState
放在不同的包中吗?这样做后需要这样做,但没有帮助:您需要在goroutineOh中运行ticker部分,好的,这就像使用ListenAndServe()如果我们需要在多端口上收听,goroutine中也需要多次使用,谢谢。使用其他软件包中的
键入GlobalState
,并在应用过程中使用不同的软件包怎么样?有什么帮助吗?是的,没有理由你不能将其放在自己的软件包中,只要使用单例模式或其他什么,如果是这样的话你不是说
type GlobalState struct {
    data map[string]interface{}
    sync.RWMutex
}

func (gs *GlobalState) Get(key string) interface{} {
    gs.RLock()
    defer gs.RUnlock()
    return gs.data[key]
}

func (gs *GlobalState) Refresh() {
    jsonFile, _ := ioutil.ReadFile(dir + "/devices.json")
    gs.Lock()
    defer gs.Unlock()
    _ = jsonFast.Unmarshal(jsonFile, &gs.data)
}

var devices GlobalState

func main() {
    t := time.NewTicker(5 * 60 * time.Second)
    for ; true; <-t.C {
         devices.Refresh()
    }
}