Map 具有并发访问的映射

Map 具有并发访问的映射,map,go,mutex,Map,Go,Mutex,当您在具有并发访问的程序中使用映射时,是否需要在函数中使用互斥来读取值?多个读取器,没有写入器是可以的: 一个作家,没有读者是可以的。(否则地图就不会有多好了。) 否则,如果至少有一个writer和至少一个writer或reader,则所有读卡器和写卡器必须使用同步来访问地图。互斥可以很好地解决这个问题。几天前我在reddit线程中回答了您的问题: 在围棋中,地图不是线程安全的。此外,数据甚至需要锁定 例如,如果有另一个goroutine是 写入相同的数据(即并发) 从您在评论中的澄清判断,也

当您在具有并发访问的程序中使用映射时,是否需要在函数中使用互斥来读取值?

多个读取器,没有写入器是可以的:

一个作家,没有读者是可以的。(否则地图就不会有多好了。)


否则,如果至少有一个writer和至少一个writer或reader,则所有读卡器写卡器必须使用同步来访问地图。互斥可以很好地解决这个问题。

几天前我在reddit线程中回答了您的问题:

在围棋中,地图不是线程安全的。此外,数据甚至需要锁定 例如,如果有另一个goroutine是 写入相同的数据(即并发)

从您在评论中的澄清判断,也将有setter函数,您的问题的答案是肯定的,您必须使用互斥来保护您的读取;你可以用一个。例如,您可以查看我编写的表数据结构(在后台使用映射)的实现(实际上是在reddit线程中链接的一个)。您可以使用它来处理并发问题

// 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")

如果您只有一个编写器,那么您可能不需要使用原子值。以下内容改编自(原版使用锁来保护写入,因此支持多个写入程序)


自2017年4月27日起,
sync.Map
已合并为Go master

这是我们一直在等待的并发映射


为什么没有使用Go并发模型,这里有一个简单的例子

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
}
类型数据管理器结构{
/**这包含到已知数据存储的连接**/
m_数据存储映射[字符串]数据存储
/**该通道用于访问数据存储地图**/
m_dataStoreChan chan map[string]接口{}
}
func newDataManager()*数据管理器{
dataManager:=新建(dataManager)
dataManager.m_dataStores=make(映射[字符串]数据存储)
dataManager.m_dataStoreChan=make(chan-map[string]接口{},0)
//并发性。。。
go func(){
为了{
挑选{

case op:=如果它是一个严格意义上的只读映射,就不需要互斥。我不太清楚,因为会有函数来设置和获取值。对于一个资源,使用完全读写器锁和映射一样快的访问速度通常是浪费的。你能详细说明一下吗?什么更合适?RW锁适合具有大量数据的资源但是它们比互斥锁有更多的开销。Map get/Set足够快,程序可能不会有足够的争用,使得更复杂的锁比简单的互斥锁提供更好的吞吐量。感谢您的澄清。您有任何关于这一问题的论文/文章可以推荐吗?但是,并发部分这篇文章的最后一段建议sync.RWMutexThings就是为什么我不能认真对待go“不需要泛型”的概念。这个概念不是说go“不需要泛型”,而是“目前没有干净的方法来实现泛型,我们需要进一步思考”例如,C++生成用于正在使用的所有可能类型组合的代码,这会增加编译时间和可执行的大小。(出于这个原因,它不使用关键点的切分,这意味着如果你的地图有大量的搅动,那么根据我上面的回答,它很可能会低于切分样式的地图)。@OmarIlias我指的是你主要设置新值(不编辑或删除现有值)的情况。请参阅:@orcaman current go sync.Map可能比哈希切分更快或更慢,即使在仅追加的情况下也是如此。这确实取决于场景。使用尽可能多的原子操作,sync.Map内部可以比传统切分快得多,因为与传统哈希桶相比,它最小化了锁定,但需要锁定。我确信e将执行一些基准测试,详细说明新的sync.Map实现的优缺点。但假设较慢是不正确的,尤其是考虑并发性。@Diegomontoya当然,这里是:,简而言之,sync.Map将更快,只有在使用的内核数大于4的情况下,如果不是这样,则仅使用mutex将是正确的最多快4倍如果有多个写入程序,没有读卡器呢?这会导致内存损坏吗?@user3125693当然。
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
}