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")
_ = jsonFast.Unmarshal(jsonFile, &devices)
在高负载下的应用程序过程中,多个 goroutine 会访问它。
现在由于该文件每 5 分钟更新一次,因此在不重新启动应用程序的情况下,我想使该地图界面无效devices
以从文件中加载新数据。
在 node.js 中我曾经使用过,delete require.cache[require.resolve("filename")]
但不确定如何在 go 中完成。
我尝试在 SetInterval func(节点版本的端口)中使用互斥锁,我从这里使用它每 5 分钟读取一次文件,但我收到此错误:
goroutine 871895 [IO wait]:
这似乎意味着 goroutine 正在等待解锁以从全局变量中读取。
代码:
var m sync.Mutex
//this function execute every 5 minute to read file and reassign to map interface.
_ = setInterval(func() {
jsonFile, _ := ioutil.ReadFile(dir + "/devices.json")
m.Lock() // used this mutex as the step may cause race condition.
_ = jsonFast.Unmarshal(jsonFile, &devices)
m.Unlock()
}, 5* 60 * 1000, false)
//this initializes at the start after which the set interval execute every 5 minute to get updated data.
jsonFile, _ := ioutil.ReadFile(dir + "/devices.json")
_ = jsonFast.Unmarshal(jsonFile, &devices)
我应该用什么方法来实现这一点?或者有什么方法可以从文件中读取/更新而不是使用映射接口来避免竞争条件和 IO 锁定?
解决方案
我想这个问题与当你试图用新数据覆盖它时你仍然有从地图中读取的 goroutines 的事实有关。我建议您使用 async.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()
}
}
然后你有安全读取(但需要做devices.Get(key)
而不是devices[key]
)和安全写入。此外,最后它被清理了一点,因此您不必重复代码以使计时器立即运行。
推荐阅读
- javascript - 试图克隆 spotify 应用程序在 localhost:3000 类型错误中出现错误:无法读取未定义的属性“url”
- c# - 使用 Postman 运行 PUT 方法时的 WebAPI 很好,使用 API 控制器运行将失败
- javascript - 从嵌套数组中过滤出空字符串
- yii - Yii 统计会员总数并显示在登陆页面上
- python - Python 如何使用 idxmax() 获取完整的行值,但基于特定字段的条件
- bootstrap-4 - 页面右下角的 Bootstrap Toast
- javascript - 如何从另一个下拉列表列出的下拉列表选择中获取值
- sql - 如何在不重复行、不同粒度的情况下合并两个表
- .net - 'OLE DB 或 ODBC 错误:[Expression.Error] 此值不支持本机查询
- react-native - 如何在反应原生表单验证的功能组件中以编程方式在 Text 中设置文本?