·
Todos os posts
go

Como garantir thread-safety em Go

Trabalhando com Mutex para garantir thread-safety em Go

Ao trabalhar com multithreading, podemos encontrar alguns desafios, sendo um deles a integridade dos dados quando um valor é acessado por serviços rodando em paralelo. Em Go, temos o Mutex para nos ajudar a sincronizar dados entre goroutines executando em múltiplas threads.

Mutex é conhecido como Exclusão Mútua — ele nos permite bloquear e desbloquear um valor enquanto o estamos modificando. Isso significa que o recurso fica bloqueado durante a atualização, e outros processos precisam aguardar até que o processo em andamento seja concluído.

Sem Mutex

Aqui está um exemplo de código sem mutex. É um programa simples que abre 10 goroutines, cada uma incrementando uma variável mil vezes. Nessa situação, podemos encontrar uma condição de corrida: múltiplas goroutines tentando atualizar o mesmo valor simultaneamente, o que pode levar a resultados imprevisíveis. O ideal seria que, após a execução, obtivéssemos 10.000 como resultado (pois 10 x 1000 = 10.000). Mas o que acontece na prática? Veja o código.

Loading...

Como você pode ver, às vezes o resultado está correto. No entanto, ao executar várias vezes, o problema aparece. Este é o ponto central: sem sincronização ou Mutex, existem condições de corrida, e durante esse tempo você pode ver resultados diferentes, como 7109. Em ambientes de produção, precisamos garantir valores consistentes para todos os processos.

  • Saída
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (without mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (without mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (without mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (without mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (without mutex): 7109
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (without mutex): 10000

Com Mutex

Agora que você entende o problema, vamos ver como corrigi-lo. Com Mutex, podemos bloquear um valor antes de alterá-lo. Se outro processo tentar acessar esse valor, ele aguardará até que a primeira interação finalize a modificação. Aqui está o código com Mutex aplicado:

Loading...

Como você pode ver, executando múltiplas vezes, o resultado é sempre o esperado. Dessa forma, conseguimos evitar condições de corrida e resultados inválidos.

  • Saída
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (with mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (with mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (with mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (with mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (with mutex): 10000
lucas@queiroz:~/git/goexamples/mutex$ go run main.go 
Final Counter (with mutex): 10000

Conclusão

Em cenários onde valores são compartilhados entre múltiplas goroutines e precisam ser consistentes entre elas, o Mutex ajuda a manter a integridade dos dados, prevenindo condições de corrida e resultados inconsistentes.