O mecanismo primário para gerenciar estado em Go ẽ
a comunicação entre canais. Um dos exemplos apresentados
foi os worker pools. No entanto, existem
algumas outras opções para gerenciar estado.
Aqui será apresentado o pacote |
|
package main |
|
import ( "fmt" "sync" "sync/atomic" ) |
|
func main() { |
|
Será utilizado um inteiro unsigned integer para representar um contador sempre positivo. |
var ops uint64 |
Um WaitGroup auxiliará a aguardar todas as goroutines finalizarem suas tarefas. |
var wg sync.WaitGroup |
Iniciaremos 50 goroutines que incrementarão o contador exatamente 1000 vezes. |
for i := 0; i < 50; i++ { wg.Add(1) |
Para incrementar o contador será utilizado
|
go func() { for c := 0; c < 1000; c++ { |
ops++ |
atomic.AddUint64(&ops, 1) |
} wg.Done() }() } |
|
Aguarda todas as goroutines finalizarem. |
wg.Wait() |
É seguro ler o contador |
fmt.Println("ops:", ops) } |
É esperado que o código realize exatamente
50.000 operações.
Se fosse utilizada a forma não-atômica de
incrementação, provavelmente o resultado
seria diferente entre as execuções, porque
as goroutines interfeririam umas com as
outras. Alẽm disso, provavelmente aconteceria
falhas de data race, que é possível visualizar
executando o código com a flag |
$ go run atomic-counters.go ops: 50000 |
Código com |
$ go run -race atomic-counters.go ================== WARNING: DATA RACE Read at 0x00c00001a0f8 by goroutine 10: main.main.func1() /.../atomic-counters.go:38 +0x46 ================== ops: 6573 Found 1 data race(s) exit status 66 |
Em seguida, será apresentado mutexes, outra ferramenta para gerenciar estado. |
Próximo exemplo: Mutexes.