Sobes.tech
Middle+

Quão seguro é passar slices para diferentes goroutines?

sobes.tech IA

Resposta da IA

Transmitir slices diretamente para diferentes goroutines não é seguro se as goroutines as modificarem simultaneamente sem sincronização ou se o slice for modificado numa goroutine após ser passado (por cópia do cabeçalho) para outra.

Razões de insegurança:

  • Array base compartilhado: Os slices são cabeçalhos (ponteiro para o array base, comprimento, capacidade) apontando para um array base comum.
  • Condição de corrida (Race Condition): Escrever simultaneamente no mesmo elemento do array base ou alterar seu tamanho a partir de diferentes goroutines levará a condições de corrida, resultados imprevisíveis e erros.

Formas seguras de trabalhar com slices em goroutines:

  1. Passar uma cópia do slice: Criar uma cópia completa do slice e passá-la. Isto é seguro, pois as goroutines trabalham com dados separados.

    // criar uma cópia completa do slice
    newSlice := make([]int, len(originalSlice))
    copy(newSlice, originalSlice)
    
  2. Usar canais: Passar os elementos do slice ou o slice completo através de canais. Os canais fornecem sincronização e isolamento de dados.

    // passar elementos através de um canal
    ch := make(chan int)
    go func() {
        for _, v := range originalSlice {
            ch <- v
        }
        close(ch)
    }()
    
    // passar o slice através de um canal
    chSlice := make(chan []int)
    go func() {
        chSlice <- originalSlice // passar por valor do cabeçalho, mas o canal sincroniza
                                // importante: não modificar originalSlice após o envio
    }()
    
  3. Sincronização com sync.Mutex ou sync.RWMutex: Proteger o acesso ao slice usando mutexes. Isto garante que apenas uma goroutine possa modificar o slice em qualquer momento.

    import "sync"
    
    var mu sync.Mutex
    var sharedSlice []int
    
    func modifySlice(index, value int) {
        mu.Lock()
        defer mu.Unlock()
        if index < len(sharedSlice) {
            sharedSlice[index] = value
        }
    }
    

Comparação de abordagens:

Abordagem Segurança Desempenho com slices grandes Complexidade
Cópia do slice Alta Menor (cópia de dados) Simples
Canais Alta Depende (custo das operações do canal) Média
Mutexes Alta Alta (se não houver conflitos fortes) Média

Assim, passar o cabeçalho do slice para diferentes goroutines sem sincronização adicional ou cópia não é seguro. É necessário usar um dos métodos acima para garantir a segurança dos dados.