Обновить значение глобальной области видимости - PullRequest
0 голосов
/ 17 января 2020

У меня есть 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)

Доступ к нему выполняется несколькими программами в течение приложения под высокой нагрузкой.

Теперь. Поскольку этот файл обновляется каждые 5 минут, поэтому без перезапуска приложения я хочу сделать этот интерфейс карты недействительным devices, чтобы из файла были загружены данные fre sh.

В node.js Я использовал delete require.cache[require.resolve("filename")], но не уверен, как это можно сделать в go.

Я пытался использовать блокировку мьютекса в SetInterval fun c (порт узла версия) Я использовал здесь , который читает файл каждые 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)

Каким должен быть мой подход для достижения этой цели? Или есть ли способ чтения / обновления из файла вместо использования интерфейса карты, чтобы избежать состояния гонки? а блокировка ввода-вывода?

1 Ответ

0 голосов
/ 17 января 2020

Я полагаю, что проблема связана с тем, что у вас все еще есть 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()
    }
}

Тогда у вас есть безопасное чтение (но вам нужно сделать devices.Get(key) вместо devices[key]), и безопасные записи. Кроме того, в конце он немного очищается, поэтому вам не нужно повторять код, чтобы таймер работал немедленно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...