«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Почему функция «append» не является потокобезопасной для одновременного доступа в Go?

Почему функция «append» не является потокобезопасной для одновременного доступа в Go?

Опубликовано 11 ноября 2024 г.
Просматривать:841

Why is `append` function not thread-safe for concurrent access in Go?

Функция добавления: не потокобезопасна для одновременного доступа

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

Это происходит потому, что в Go ни одно значение не является изначально безопасным для одновременного чтения и записи. Срезы, представленные заголовками срезов, не являются исключением. В предоставленном коде наблюдаются гонки данных из-за одновременного доступа:

destSlice := make([]myClass, 0)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        destSlice = append(destSlice, tmpObj)
    }(myObject)
}
wg.Wait()

Чтобы проверить наличие состязаний в данных, выполните следующую команду:

go run -race play.go

Вывод предупредит вас о наличии данных расы:

WARNING: DATA RACE
...

Решение проблем параллелизма

Чтобы решить эту проблему, защитите доступ на запись к destSlice, используя sync.Mutex:

var (
    mu        = &sync.Mutex{}
    destSlice = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        mu.Lock()
        destSlice = append(destSlice, tmpObj)
        mu.Unlock()
    }(myObject)
}
wg.Wait()

В качестве альтернативы рассмотрите возможность использования канала для асинхронной обработки добавлений:

var (
    appendChan = make(chan myClass)
    destSlice  = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        appendChan 
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3