Planejamento de Tarefas
sync.WaitGroup
package main
import (
"fmt"
"sync"
)
// Exemplo de uso de goroutines
func imprimirMensagem() {
fmt.Println("Goroutine executada")
}
var grupo sync.WaitGroup
func tarefaWaitGroup(id int) {
defer grupo.Done()
fmt.Println(id, "tarefa concluída")
}
func main() {
go imprimirMensagem()
for i := 0; i < 10; i++ {
grupo.Add(1)
go tarefaWaitGroup(i)
}
grupo.Wait()
fmt.Println("Final do programa")
}
Saída:
Goroutine executada
0 tarefa concluída
1 tarefa concluída
2 tarefa concluída
3 tarefa concluída
...
9 tarefa concluída
Final do programa
sync.Once
package main
import (
"fmt"
"sync"
)
var umaVez sync.Once
func inicializar() {
fmt.Println("Inicialização executada uma vez")
}
func operacaoUnica() {
umaVez.Do(func() {
inicializar()
})
}
func main() {
operacaoUnica()
operacaoUnica()
}
Saída:
Inicialização executada uma vez
sync.Cond
package main
import (
"fmt"
"sync"
"time"
)
var pronto bool
func produtor(cond *sync.Cond) {
fmt.Println("Produtor iniciado")
time.Sleep(50 * time.Millisecond)
cond.L.Lock()
time.Sleep(100 * time.Millisecond)
pronto = true
fmt.Println("Produtor finalizado")
cond.L.Unlock()
cond.Broadcast()
fmt.Println("Notificando consumidores")
}
func consumidor(nome string, cond *sync.Cond) {
fmt.Printf("Consumidor %s iniciado\n", nome)
cond.L.Lock()
for !pronto {
fmt.Printf("Consumidor %s aguardando\n", nome)
cond.Wait()
}
fmt.Printf("Consumidor %s trabalhando\n", nome)
time.Sleep(50 * time.Millisecond)
fmt.Printf("Consumidor %s finalizado\n", nome)
cond.L.Unlock()
}
func main() {
cond := sync.NewCond(&sync.Mutex{})
tarefas := []string{"A", "B"}
for _, t := range tarefas {
go consumidor(t, cond)
}
go produtor(cond)
time.Sleep(2 * time.Second)
fmt.Println("Fim do programa")
}
Saída:
Produtor iniciado
Consumidor A iniciado
Consumidor B iniciado
Consumidor A aguardando
Consumidor B aguardando
Produtor finalizado
Notificando consumidores
Consumidor A trabalhando
Consumidor A finalizado
Consumidor B trabalhando
Consumidor B finalizado
Fim do programa
runtime
package main
import (
"fmt"
"runtime"
"time"
)
func lavarRoupas(iter int) {
for i := 0; i < iter; i++ {
if i == 2 {
defer fmt.Println("Lavar roupas finalizado abruptamente")
runtime.Goexit()
}
fmt.Println("Lavando:", i)
runtime.Gosched()
}
}
func cozinhar(iter int) {
for i := 0; i < iter; i++ {
if i == 2 {
defer fmt.Println("Cozinhar finalizado abruptamente")
runtime.Goexit()
}
fmt.Println("Cozinhando:", i)
runtime.Gosched()
}
}
func main() {
runtime.GOMAXPROCS(1)
go lavarRoupas(5)
go cozinhar(5)
time.Sleep(3 * time.Second)
fmt.Println("Todas as tarefas concluídas")
}
Saída:
Cozinhando: 0
Lavando: 0
Cozinhando: 1
Lavando: 1
Cozinhar finalizado abruptamente
Lavar roupas finalizado abruptamente
Todas as tarefas concluídas
Canais
package main
import (
"fmt"
"time"
)
func esperarTarefa(canal <-chan int) {
fmt.Println("Esperando")
<-canal
fmt.Println("Recebeu sinal")
}
func executarTarefa(canal chan int) {
defer close(canal)
fmt.Println("Executando")
time.Sleep(100 * time.Millisecond)
fmt.Println("Executou")
}
func main() {
canal := make(chan int)
go esperarTarefa(canal)
go esperarTarefa(canal)
go executarTarefa(canal)
time.Sleep(2 * time.Second)
}
Saída:
Executando
Esperando
Esperando
Executou
Recebeu sinal
Recebeu sinal
Comunicação de Dados
Canais com Buffer
package main
import (
"fmt"
"time"
)
func main() {
canal := make(chan int, 5)
go func() {
for i := 0; i < 5; i++ {
fmt.Println("Enviando:", i)
canal <- i
}
close(canal)
}()
go func() {
for v := range canal {
fmt.Println("ReceptorA:", v)
}
}()
go func() {
for v := range canal {
fmt.Println("ReceptorB:", v)
}
}()
time.Sleep(1 * time.Second)
}
Saída:
Enviando: 0
Enviando: 1
Enviando: 2
Enviando: 3
Enviando: 4
ReceptorA: 0
ReceptorB: 1
ReceptorA: 2
ReceptorB: 3
ReceptorA: 4
Canais com Select
package main
import (
"fmt"
"time"
)
func main() {
canal1 := make(chan int, 1)
canal2 := make(chan int, 1)
go func() {
time.Sleep(200 * time.Millisecond)
canal1 <- 11
close(canal1)
}()
go func() {
time.Sleep(500 * time.Millisecond)
canal2 <- 111
close(canal2)
}()
for i := 0; i < 10; i++ {
select {
case d, ok := <-canal1:
if ok {
fmt.Println("Canal1:", d)
} else {
fmt.Println("Canal1 fechado")
}
case d, ok := <-canal2:
if ok {
fmt.Println("Canal2:", d)
} else {
fmt.Println("Canal2 fechado")
}
default:
fmt.Println("Default")
}
time.Sleep(200 * time.Millisecond)
}
}
Saída:
Default
Default
Canal1: 11
Canal1 fechado
Canal2: 111
Canal1 fechado
Canal2 fechado
Canal2 fechado
Canal2 fechado
Canal1 fechado
sync.Mutex
package main
import (
"fmt"
"sync"
)
var total int
func main() {
lock := sync.Mutex{}
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
lock.Lock()
total++
lock.Unlock()
}()
}
wg.Wait()
fmt.Println("Total:", total)
}
Saída:
Total: 100
atomic
package main
import (
"fmt"
"sync"
"sync/atomic"
)
var contagem int64
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&contagem, 1)
}()
}
wg.Wait()
fmt.Println("Contagem:", contagem)
}
Saída:
Contagem: 100
sync.Map
package main
import (
"fmt"
"sync"
"time"
)
var mapaConcorrente sync.Map
var wg sync.WaitGroup
func main() {
// Operações básicas
mapaConcorrente.Store("chave", "valor")
v, ok := mapaConcorrente.Load("chave")
fmt.Printf("Load: chave=%v, valor=%v, ok=%v\n", "chave", v, ok)
novaChave := "idade"
novoValor := "25"
v, carregou := mapaConcorrente.LoadOrStore(novaChave, novoValor)
fmt.Printf("LoadOrStore: chave=%v, valor=%v, carregou=%v\n", novaChave, v, carregou)
mapaConcorrente.Delete(novaChave)
v, ok = mapaConcorrente.LoadAndDelete("chave")
fmt.Printf("LoadAndDelete: chave=%v, valor=%v\n", "chave", v)
for i := 0; i < 5; i++ {
mapaConcorrente.Store(i, i*10)
}
mapaConcorrente.Range(func(k, v interface{}) bool {
fmt.Printf("Range: chave=%v, valor=%v\n", k, v)
return true
})
// Concorrência
wg.Add(3)
go func() {
defer wg.Done()
for i := 0; i < 3; i++ {
mapaConcorrente.Store(i*100, i)
}
}()
time.Sleep(100 * time.Millisecond)
go func() {
defer wg.Done()
mapaConcorrente.Range(func(k, v interface{}) bool {
fmt.Println("LeitorA:", k, v)
return true
})
}()
go func() {
defer wg.Done()
mapaConcorrente.Range(func(k, v interface{}) bool {
fmt.Println("LeitorB:", k, v)
return true
})
}()
wg.Wait()
}
Saída:
Load: chave=chave, valor=valor, ok=true
LoadOrStore: chave=idade, valor=25, carregou=false
LoadAndDelete: chave=chave, valor=valor
Range: chave=0, valor=0
Range: chave=1, valor=10
Range: chave=2, valor=20
Range: chave=3, valor=30
Range: chave=4, valor=40
LeitorA: 0 0
LeitorB: 0 0
LeitorA: 1 10
LeitorB: 1 10
...
sync.Pool
package main
import (
"fmt"
"sync"
"sync/atomic"
)
var criados int32
var grupo sync.WaitGroup
func main() {
pool := &sync.Pool{
New: func() interface{} {
atomic.AddInt32(&criados, 1)
buf := make([]byte, 16)
return &buf
},
}
numWorkers := 5
grupo.Add(numWorkers)
for i := 0; i < numWorkers; i++ {
go func() {
defer grupo.Done()
buf := pool.Get()
defer pool.Put(buf)
}()
}
grupo.Wait()
fmt.Println("Objetos criados:", criados)
}
Saída:
Objetos criados: 3