Можно ли проверить, было ли установлено поле, не вызывая условия гонки? - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть структура, которая совместно используется многими программами, и я хотел бы сократить количество вычислений одного поля в структуре, если это возможно. Вероятно, проще показать:

type Container struct {
    Items []Item
    mu    sync.RWMutex
}

(container *Container) func loadContainer() {
    if container.Items != nil { // This is detected as a race condition by go
        return 
    }
    container.mu.Lock()
    container.Items = loadItems() // Does some logic that I would like to avoid repeating
    container.mu.Unlock()
}

Есть ли безопасный способ выполнить sh это? Это почти как если бы я хотел состояние гонки, где я не против, если оно записано несколько раз, но первый поток, который это сделает, должен предотвратить последующее чтение. Довольно плохо знаком с go и параллелизмом в целом.

1 Ответ

1 голос
/ 13 февраля 2020

При вашем подходе вы должны сначала заблокировать, прежде чем сможете проверить, установлен ли Items. Например:

func (container *Container) loadContainer() {
    container.mu.Lock()
    defer container.mu.Unlock()

    if container.Items != nil {
        return
    }

    container.Items = loadItems()
}

Но sync.Once обеспечивает лучшую и более быструю альтернативу. Также было бы целесообразно скрыть поле Items, чтобы на него нельзя было случайно сослаться. Экспортированная функция должна позаботиться об инициализации и вернуть значение, инициализированное только один раз:

type Container struct {
    once  sync.Once
    items []Item
}

func (container *Container) GetItems() []Item {
    container.once.Do(func() {
        container.Items = loadItems()
    })
    return container.items
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...