"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Por que a função `append` não é segura para threads para acesso simultâneo no Go?

Por que a função `append` não é segura para threads para acesso simultâneo no Go?

Publicado em 2024-11-11
Navegar:568

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

Função de acréscimo: não é segura para thread para acesso simultâneo

Ao utilizar goroutines simultaneamente para anexar elementos a uma fatia dentro de um loop for, anomalias nos dados podem surgir. Dados ausentes ou em branco podem aparecer na fatia resultante, indicando possíveis corridas de dados.

Isso ocorre porque em Go, nenhum valor é intrinsecamente seguro para leitura e gravação simultâneas. As fatias, representadas por cabeçalhos de fatia, não são exceção. O código fornecido exibe corridas de dados devido ao acesso simultâneo:

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()

Para verificar a presença de corridas de dados, execute o seguinte comando:

go run -race play.go

A saída irá alertá-lo sobre os dados corridas:

WARNING: DATA RACE
...

Resolvendo problemas de simultaneidade

Para resolver esse problema, proteja o acesso de gravação ao destSlice empregando um 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()

Como alternativa, considere usar um canal para lidar de forma assíncrona com os anexos:

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 
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3