RW блокируется операциями CRUD - PullRequest
0 голосов
/ 24 апреля 2019

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

type Data struct {
    sync.RWMutex
    fooMap map[string]Foo
}

func (d *Data) AddFoo(foo Foo) {
    d.Lock()
    defer d.Unlock()

    d.fooMap[foo.getName()] = foo
}

func (d *Data) GetFoo(name string) Foo {
    return d.fooMap[name]
}

func (d *Data) RemoveFoo(name string) Foo {
    d.Lock()
    defer d.Unlock()

    var foo = self.fooMap[name]
    if foo != nil {
        delete(d.fooMap, name)
    }
    return foo
}

func (d *Data) HasFoo(name string) bool {
    return d.fooMap[name] != nil
}

В поисках эффективного подхода, при котором я не блокирую при чтении из словаря, а блокирую только в методах AddFoo и RemoveFoo.

Редактировать Контекст немного отличается, код не будет выполняться goroutines, но будет использоваться на сервере, где происходит множество одновременных запросов.

Редактировать 2 В случае двух карт

type Data struct {
    sync.RWMutex
    BarMutex sync.RWMutex{}
    fooMap map[string]Foo
    barMap map[string]Bar
}

// for Foo
func (d *Data) AddFoo(foo Foo) {
    d.Lock()
    defer d.Unlock()

    d.fooMap[foo.getName()] = foo
}

func (d *Data) GetFoo(name string) Foo {
    return d.fooMap[name]
}

// for Bar
func (d *Data) AddBar(bar Bar) {
    d.BarMutex.Lock()
    defer d.BarMutex.Unlock()

    d.barMap[bar.getName()] = bar
}

func (d *Data) GetBar(name string) Bar {
    d.BarMutex.RLock()
    defer d.BarMutex.RUnlock();
    return d.barMap[name]
}

Добавление еще нескольких методов.

1 Ответ

1 голос
/ 24 апреля 2019

код не будет выполняться программами, но будет использоваться на сервере, где у меня множество одновременных запросов

Если они параллельны, они находятся в процедурах - например, если вы используете сервер net/http, каждый запрос находится в своей собственной программе. Других механизмов параллелизма не существует, поэтому, если у вас есть параллелизм, вы используете подпрограммы, даже если ваш код их явно не запускает.

Вы не можете "блокировать только в методах AddFoo и RemoveFoo"; это не так, как синхронизация работает. Если вы делитесь данными, вам придется получить блокировку для чтения, и вы заблокируете некоторые операции чтения, если они происходят одновременно с записями. Если вы не приобрели блокировку для чтения, у вас есть состояние гонки.

func (d *Data) GetFoo(name string) Foo {
    d.RLock()
    d.RUnlock()
    return d.fooMap[name]
}

Альтернативой может быть совместное использование памяти путем передачи . Это более сложный рефакторинг, и есть много способов сделать это в зависимости от ваших конкретных потребностей; это не то, что я мог бы предложить для решения на основе обобщенного примера типа "Foo".

...