high angle view of people on bicycle

Como resolver race condition com sync/atomic

Algum tempo atrás, publicamos um post aqui no blog explicando como resolver race condition utilizando mutex e channels.

Embora o conteúdo daquele post continue sendo válido, para alguns casos mais simples de race condition, como por exemplo o do post, podemos utilizar o package sync/atomic para nos auxiliar.

Para dar o ponta pé inicial, vamos escrever um código que não irá funcionar corretamente por haver race condition.

package main

import (
	"fmt"
	"sync"
)

func main() {
	var total int64

	var wg sync.WaitGroup

	for i := 0; i < 50; i++ {
		wg.Add(1)

		go func() {
			for c := 0; c < 1000; c++ {
				total += int64(c)
			}
			wg.Done()
		}()
	}

	wg.Wait()

	fmt.Println(total)
}

Esse simples programa irá iniciar 50 goroutines, onde cada uma delas irá somar o valor de c (que vai de 0 até 999) à variável total. Reparem também que é preciso fazer um casting de c, pois seu tipo será int e precisamos que eles seja int64.

Ao executar esse código 3 vezes, obtive os seguintes resultados:

Claramente o programa não está funcionando corretamente. Isso acontece pois não existe nenhum controle de acesso a variável total, ou seja, não existe uma garantia que a cada iteração do looping dentro das 50 goroutines, o valor da variável é realmente o último atualizado.

Como eu disse no inicio do post, podemos utilizar mutex ou channels para resolver esse problema. No entanto, devido ao tamanho de sua simplicidade, vamos utilizar o package sync/atomic.

Se você ainda não conhece, esse package fornece algumas funções que nos ajudam a lidar com sincronização e estado de variáveis que são acessadas simultaneamente por múltiplas goroutines. Em outras palavras, ele nos ajuda a resolver o problema que estamos tendo nesse programa.

Resolvendo o race condition

Na linha 19, onde fazemos o total += int64(c), vamos mudar para o seguinte código:

atomic.AddInt64(&total, int64(c))

Agora, ao realizar 3 execuções do programa novamente, os resultados que obtive foram:

Problema resolvido de forma simples e elegante.

PONTO DE ATENÇÃO!!!

Como a própria documentação diz, as funções contidas nesse package requerem muito cuidado para serem utilizadas de forma correta. Exceto para alguns casos especiais, a melhor forma de lidar com sincronização é através de channels ou ferramentas fornecidas pelo package sync.

Deixem suas dúvidas nos comentários.

Até a próxima!


Se inscreva na nossa newsletter

* indicates required

2 comentários sobre “Como resolver race condition com sync/atomic

Deixe uma resposta