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

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

 jimt16 июн. 2012 г., 14:40
Если это карта только для чтения, мьютекс не должен быть необходим.
 user124374616 июн. 2012 г., 14:47
Мне было не очень понятно, так как будут функции для установки и получения значений.

Ответы на вопрос(7)

то вы, вероятно, можете избежать использования атомарного значения. Следующее адаптировано из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.
    }

есть простой пример ...

type DataManager struct {
    /** This contain connection to know dataStore **/
    m_dataStores map[string]DataStore

    /** That channel is use to access the dataStores map **/
    m_dataStoreChan chan map[string]interface{}
}

func newDataManager() *DataManager {
    dataManager := new(DataManager)
    dataManager.m_dataStores = make(map[string]DataStore)
    dataManager.m_dataStoreChan = make(chan map[string]interface{}, 0)
    // Concurrency...
    go func() {
        for {
            select {
            case op := <-dataManager.m_dataStoreChan:
                if op["op"] == "getDataStore" {
                    storeId := op["storeId"].(string)
                    op["store"].(chan DataStore) <- dataManager.m_dataStores[storeId]
                } else if op["op"] == "getDataStores" {
                    stores := make([]DataStore, 0)
                    for _, store := range dataManager.m_dataStores {
                        stores = append(stores, store)
                    }
                    op["stores"].(chan []DataStore) <- stores
                } else if op["op"] == "setDataStore" {
                    store := op["store"].(DataStore)
                    dataManager.m_dataStores[store.GetId()] = store
                } else if op["op"] == "removeDataStore" {
                    storeId := op["storeId"].(string)
                    delete(dataManager.m_dataStores, storeId)
                }
            }
        }
    }()

    return dataManager
}

/**
 * Access Map functions...
 */
func (this *DataManager) getDataStore(id string) DataStore {
    arguments := make(map[string]interface{})
    arguments["op"] = "getDataStore"
    arguments["storeId"] = id
    result := make(chan DataStore)
    arguments["store"] = result
    this.m_dataStoreChan <- arguments
    return <-result
}

func (this *DataManager) getDataStores() []DataStore {
    arguments := make(map[string]interface{})
    arguments["op"] = "getDataStores"
    result := make(chan []DataStore)
    arguments["stores"] = result
    this.m_dataStoreChan <- arguments
    return <-result
}

func (this *DataManager) setDataStore(store DataStore) {
    arguments := make(map[string]interface{})
    arguments["op"] = "setDataStore"
    arguments["store"] = store
    this.m_dataStoreChan <- arguments
}

func (this *DataManager) removeDataStore(id string) {
    arguments := make(map[string]interface{})
    arguments["storeId"] = id
    arguments["op"] = "removeDataStore"
    this.m_dataStoreChan <- arguments
}

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

// 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")
 23 мая 2016 г., 05:51
Именно поэтому я не могу всерьез воспринимать идею о том, что «не нужны дженерики».
 19 сент. 2016 г., 15:42
Понятие «что Go» не нуждается в генериках »; но "в настоящее время нет чистого способа реализации дженериков, нам нужно подумать об этом еще немного". Например, C ++ генерирует код для всех возможных комбинаций используемых типов, что увеличивает время компиляции и размеры исполняемого файла на необоснованную величину.
Решение Вопроса

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

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

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

 05 мар. 2019 г., 16:10
@ user3125693 Конечно.
 21 апр. 2018 г., 01:39
А как насчет нескольких писателей, без читателей? Не приведет ли это к повреждению памяти?

этот Reddit тема несколько дней назад:

In Go, maps are not thread-safe. Also, data requires locking even for reading if, for example, there could be another goroutine that is writing the same data (concurrently, that is).

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

 09 нояб. 2012 г., 20:44
Можете ли вы уточнить немного, пожалуйста? Что подойдет лучше?
 31 авг. 2014 г., 02:52
Тем не менее, раздел параллелизма этого постаblog.golang.org/go-maps-in-action предлагает sync.RWMutex
 11 нояб. 2012 г., 23:02
Блокировки RW хороши для ресурсов с большим количеством конфликтов, но они имеют больше накладных расходов, чем мьютекс. Получение / набор карт достаточно быстр, чтобы программа, скорее всего, не имела достаточных конфликтов, чтобы более сложная блокировка обеспечивала лучшую пропускную способность, чем простой мьютекс.
 08 нояб. 2012 г., 06:02
обычно расточительно использовать полную блокировку чтения-записи для ресурса, доступного так же быстро, как карта
 12 нояб. 2012 г., 08:33
Спасибо тебе за пояснение. Есть ли у вас какие-либо статьи / статьи, которые вы можете порекомендовать по этому вопросу?

sync.Map объединен с Go master с 27 апреля 2017 года.

Это та карта, которую мы все ждали.

https://github.com/golang/go/blob/master/src/sync/map.go

https://godoc.org/sync#Map

 26 авг. 2017 г., 06:50
 31 мая 2017 г., 04:51
@orcaman current go sync.Map может быть быстрее или медленнее, чем shh-sharded, даже в вашем случае только для добавления. Это действительно зависит от сценария. Используя как можно больше атомарных операций, внутренняя структура sync.Map может быть намного быстрее, чем традиционное разбиение, поскольку она минимизирует блокировку по сравнению с традиционным хеш-контейнером, но требует блокировки. Я уверен, что будут проведены тесты, которые детализируют приятные и болезненные моменты новой реализации sync.Map. Но предполагать, что это медленнее, не правильно, особенно учитывая параллелизм.
 15 мая 2017 г., 09:28
Хороший. Обратите внимание, что новый тип sync.Map предназначен для карт, предназначенных только для добавления (по этой причине он не использует шардинг ключей, что означает, что если ваша карта имеет большой отток, она, скорее всего, будет хуже работать с картами стиля штриховки мой ответ выше).
 23 мая 2017 г., 17:28
@orcaman, что вы подразумеваете под картами только для добавления?
 24 мая 2017 г., 11:53
@ OmarIlias Я имею в виду случаи, когда вы в основном устанавливаете новые значения (без редактирования или удаления существующих значений). Видеть это:github.com/golang/go/issues/20360

import (
    "sync"
)

type AtomicMap struct {
    data   map[string]string
    rwLock sync.RWMutex
}

func (self *AtomicMap) Get(key string) (string, bool) {
    self.rwLock.RLock()
    defer self.rwLock.RUnlock()
    val, found := self.data[key]
    return val, found
}

func (self *AtomicMap) Set(key, val string) {
    self.rwLock.Lock()
    defer self.rwLock.Unlock()
    self.data[key] = val
}

Ваш ответ на вопрос