Как решить параллельный доступ к карте Голанга? - PullRequest
0 голосов
/ 26 сентября 2018

Теперь у меня есть карта только с одной процедурой записи / удаления и многими программами чтения, есть некоторые решения для Карты с одновременным доступом , такие как RWMutex, sync.map, concurrent-map, sync.atomic, sync.Value, какой лучший выбор для меня?

Блокировка чтения RWMutex немного избыточна

sync.map и фокус параллельной карты на многих подпрограммах записи

1 Ответ

0 голосов
/ 26 сентября 2018

Ваш вопрос немного расплывчатый, поэтому я разобью его.

Какую форму одновременного доступа я должен использовать для карты?

Выборзависит от производительности, которую вы требуете от карты.Я бы выбрал простой подход на основе мьютекса (или RWMutex).

Конечно, вы можете получить лучшую производительность от параллельной карты .sync.Mutex блокирует все корзин карт, тогда как на параллельной карте у каждой корзины есть свои sync.Mutex.

Опять же - все зависит от масштаба вашей программы итребуемая производительность.

Как бы я использовал мьютекс для одновременного доступа?

Чтобы убедиться, что карта используется правильно, вы можете заключить ее в struct.

type Store struct {
    Data              map[T]T
}

Это более объектно-ориентированное решение, но оно позволяет нам гарантировать, что любые операции чтения / записи выполняются одновременно.Кроме того, мы можем легко хранить другую информацию, которая может быть полезна для отладки или безопасности, например, автор.

Теперь мы реализуем это с помощью набора методов, таких как:

mux sync.Mutex

// New initialises a Store type with an empty map
func New(t, h uint) *Store {
    return &Store{
        Data:     map[T]T{},
    }
}

// Insert adds a new key i to the store and places the value of x at this location
// If there is an error, this is returned - if not, this is nil
func (s *Store) Insert(i, x T) error {
    mux.Lock()
    defer mux.Unlock()
    _, ok := s.Data[i]
    if ok {
        return fmt.Errorf("index %s already exists; use update", i)
    }
    s.Data[i] = x
    return nil
}

// Update changes the value found at key i to x
// If there is an error, this is returned - if not, this is nil
func (s *Store) Update(i, x T) error {
    mux.Lock()
    defer mux.Unlock()
    _, ok := s.Data[i]
    if !ok {
        return fmt.Errorf("value at index %s does not exist; use insert", i)
    }
    s.Data[i] = x
    return nil
}

// Fetch returns the value found at index i in the store
// If there is an error, this is returned - if not, this is nil
func (s *Store) Fetch(i T) (T, error) {
    mux.Lock()
    defer mux.Unlock()
    v, ok := s.Data[i]
    if !ok {
        return "", fmt.Errorf("no value for key %s exists", i)
    }
    return v, nil
}

// Delete removes the index i from store
// If there is an error, this is returned - if not, this is nil
func (s *Store) Delete(i T) (T, error) {
    mux.Lock()
    defer mux.Unlock()
    v, ok := s.Data[i]
    if !ok {
        return "", fmt.Errorf("index %s already empty", i)
    }
    delete(s.Data, i)
    return v, nil
}

В моем решении я использовал простой sync.Mutex - но вы можете просто изменить этот код, чтобы приспособить RWMutex.

Я рекомендую вам взглянуть на Как использовать RWMutex в Golang.

...