Подтвердить что ты не робот

Карта с одновременным доступом

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

4b9b3361

Ответ 1

Несколько читателей, нет писателей в порядке:

https://groups.google.com/d/msg/golang-nuts/HpLWnGTp-n8/hyUYmnWJqiQJ

Один писатель, нет читателей. (Карты были бы не очень хорошими в противном случае.)

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

Ответ 3

Я ответил на ваш вопрос в этом reddit thread несколько дней назад:

В Go карты не являются потокобезопасными. Кроме того, данные требуют блокировки даже для если, к примеру, может быть другой горутин, который записывая одни и те же данные (одновременно).

Судя по вашим пояснениям в комментариях, что также будут функции setter, ответ на ваш вопрос - да, вам придется защищать ваши чтения с помощью мьютекса; вы можете использовать RWMutex. В качестве примера вы можете посмотреть источник реализации структуры данных таблицы (использует карту за кулисами), которую я написал (на самом деле тот, который связан в reddit нить).

Ответ 4

Вы можете использовать concurrent-map для обработки усилий concurrency для вас.

// Create a new map.
map := cmap.NewConcurrentMap()

// Add item to map, adds "bar" under key "foo"
map.Add("foo", "bar")

// Retrieve item from map.
tmp, ok := map.Get("foo")

// Checks if item exists
if ok == true {
    // Map stores items as interface{}, hence we'll have to cast.
    bar := tmp.(string)
}

// Removes item under key "foo"
map.Remove("foo")

Ответ 5

Если у вас есть только один писатель, тогда вы, вероятно, можете уйти от использования атомного значения. Ниже приведено https://golang.org/pkg/sync/atomic/#example_Value_readMostly (оригинал использует блокировки для защиты записи, поэтому поддерживает несколько авторов)

type Map map[string]string
    var m Value
    m.Store(make(Map))

read := func(key string) (val string) { // read from multiple go routines
            m1 := m.Load().(Map)
            return m1[key]
    }

insert := func(key, val string) {  // update from one go routine
            m1 := m.Load().(Map) // load current value of the data structure
            m2 := make(Map)      // create a new map
            for k, v := range m1 {
                    m2[k] = v // copy all data from the current object to the new one
            }
            m2[key] = val // do the update that we need (can delete/add/change)
            m.Store(m2)   // atomically replace the current object with the new one
            // At this point all new readers start working with the new version.
            // The old version will be garbage collected once the existing readers
            // (if any) are done with it.
    }