Как заблокировать индекс конкретной карты для одновременного чтения / записи в Голанге - PullRequest
0 голосов
/ 14 ноября 2018

Я хотел знать, есть ли способ заблокировать только индекс на карте во время одновременного чтения / записи. Я довольно новичок в Голанге и параллелизме, извините, если ответ очевиден.

func Check(a, b []string) map[string]int {
    var res = make(map[string]int)
    go func() {
        for _, v := range a {
            res[v]++
        }
    }()
    go func() {
        for _, v := range b {
            res[v]++
        }
    }()
    return res
}

В конечном итоге этот фрагмент кода начинает паниковать из-за одновременного чтения / записи карты. Поэтому мы должны добавить мьютекс, чтобы заблокировать карту.

var m sync.Mutex
go func() {
    for _, v := range a {
        m.Lock()
        res[v]++
        m.Unlock()
    }
}()
go func() {
    for _, v := range b {
        m.Lock()
        res[v]++
        m.Unlock()
    }
}()

Но из моего понимания m.lock() заблокирует всю мою карту? Разве это не слишком много, блокируя все? Это дало о себе знать, так как я думал, что этот кусок кода не может быть быстрее, чем работать линейно. Могу ли я заблокировать только карту на map["some key"], чтобы моя вторая программа все еще могла писать на map["some other key"]?

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

С GO 1.9 Примечания к выпуску

Параллельная карта

Новый тип карты в пакете синхронизации представляет собой параллельную карту с загрузками, сохранением и удалением с амортизированной постоянной времени. Для нескольких программ безопасно вызывать методы Map одновременно.

GO Team построил один для вас!

0 голосов
/ 14 ноября 2018

Карты сами по себе не заботятся о блокировках, поэтому любая манипуляция ими при выполнении нескольких операций (или чтение во время манипуляции) потребует некоторой синхронизации (например, sync.Mutex).Хотя есть и более причудливые вещи, которые вы можете сделать.

RW Mutex

В зависимости от вашего варианта использования вы можете получить немного более изящного использования и использовать sync.RWMutex.Это позволит одновременное чтение, в то же время безопасно блокируя любую запись.Например:

package main

import (
    "sync"
    "time"
)

func main() {
    m := map[int]int{}
    lock := sync.RWMutex{}

    go func() {
        // Writer
        for range time.Tick(250 * time.Millisecond) {
            // Notice that this uses Lock and NOT RLock
            lock.Lock()
            m[5]++
            m[6] += 2
            lock.Unlock()
        }
    }()

    go func() {
        for range time.Tick(250 * time.Millisecond) {
            lock.RLock()
            println(m[5])
            lock.RUnlock()
        }
    }()

    for range time.Tick(250 * time.Millisecond) {
        lock.RLock()
        println(m[6])
        lock.RUnlock()
    }
}

Это не дает вам механизм блокировки ключей.

sync.Map

sync.Map предоставляется стандартной библиотекой и является надежным.У него более точная блокировка.

package main

import (
    "sync"
    "time"
)

func main() {
    m := sync.Map{}

    go func() {
        // Writer
        for range time.Tick(250 * time.Millisecond) {
            value, _ := m.LoadOrStore(5, 0)
            m.Store(5, value.(int)+1)
            value, _ = m.LoadOrStore(6, 0)
            m.Store(6, value.(int)+2)
        }
    }()

    go func() {
        for range time.Tick(250 * time.Millisecond) {
            value, _ := m.LoadOrStore(5, 0)
            println(value.(int))
        }
    }()

    for range time.Tick(250 * time.Millisecond) {
        value, _ := m.LoadOrStore(6, 0)
        println(value.(int))
    }
}

Обратите внимание, что в коде нет мьютексов.Также обратите внимание, что вы имеете дело с пустыми интерфейсами ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...