Подпадает ли sync.Map LoadOrStore к условиям гонки?

Я использую метод sync.MapLoadOrStore в Go. Я пытаюсь понять, может ли возникнуть состояние гонки, приводящее к множественным вычислениям функции создания ценности. Я пытаюсь понять, верно ли это и как с этим правильно справиться.

package main

import (
    "fmt"
    "sync"
)

type HashIDMap struct {
    m sync.Map
}

func (hm *HashIDMap) GetOrCreate(key, value string, createFunc func(string, string)) string {
    actual, loaded := hm.m.LoadOrStore(key, value)
    if !loaded {
        // If the value was not loaded, it means we stored it and need to create the database entry
        createFunc(key, value)
    }
    return actual.(string)
}

func createDatabaseEntry(key, value string) {
    // Simulate database entry creation
    fmt.Printf("Creating database entry for key: %s with value: %s\n", key, value)
}

func main() {
    hm := &HashIDMap{}

    var wg sync.WaitGroup
    wg.Add(2)

    go func() {
        defer wg.Done()
        id := hm.GetOrCreate("hash_1", "id_1", createDatabaseEntry)
        fmt.Println("Goroutine 1 got ID:", id)
    }()

    go func() {
        defer wg.Done()
        id := hm.GetOrCreate("hash_1", "id_1", createDatabaseEntry)
        fmt.Println("Goroutine 2 got ID:", id)
    }()

    wg.Wait()
}

Я читал предположения, что createFunc действительно может быть выполнен более одного раза из-за состояния гонки.

Насколько я понимаю, это именно то, что LoadOrStore пытается решить, но теперь я больше не уверен, действительно ли возможно состояние гонки.

Возможно ли, чтобы createDatabaseEntry вызывался дважды для одного и того же ключа?

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
0
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это не приводит к состоянию гонки. Предложение, которое вы прочитали, неверно. В документации sync.Map говорится (выделено мной):

В терминологии модели памяти Go Map организует так, что операция записи «синхронизируется перед» любой операцией чтения, которая наблюдает эффект записи, где операции чтения и записи определяются следующим образом. Load, LoadAndDelete, LoadOrStore, Swap, CompareAndSwap и CompareAndDelete — операции чтения; Удаление, LoadAndDelete, Store и Swap — это операции записи; LoadOrStore — это операция записи, когда она возвращает загруженное значение false.

Поэтому, как и следовало ожидать, вызов LoadOrStore, который возвращает false (операция записи), гарантированно произойдет до вызова LoadOrStore, который возвращает true (операция чтения) для того же ключа.

Это означает, что только одна из горутин, одновременно вызывающих LoadOrStore с одним и тем же ключом, увидит loaded=false и вызовет createDatabaseEntry.

Другие вопросы по теме