Programação Assíncrona em Go: guia completo com prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Programação Assíncrona em Go: da teoria à prática



Go (Golang) é famoso por seu suporte nativo à programação assíncrona. Ao contrário de muitas outras linguagens, onde a assincronicidade exige bibliotecas complexas e callbacks, Go oferece primitivas elegantes e poderosas: goroutines e canais (channels). Neste guia, abordaremos todos os conceitos-chave na prática, para que você possa escrever código paralelo eficiente em Go.



O que são Goroutines?



Uma goroutine é uma thread de execução leve, gerenciada pelo runtime do Go. Ao contrário das threads do sistema, as goroutines consomem muito poucos recursos (apenas alguns kilobytes de pilha), permitindo executar milhares ou até milhões de goroutines simultaneamente.



Iniciar uma goroutine é muito simples — basta adicionar a palavra-chave go antes da chamada de função:



package main

import ( "fmt" "time")

func sayHello() { fmt.Println("Olá da goroutine!")}

func main() { go sayHello() // Inicia a goroutine time.Sleep(time.Millisecond * 100) // Dá tempo para a goroutine executar fmt.Println("Função principal finalizada")}


Observe: se não adicionarmos time.Sleep, o programa pode terminar antes que a goroutine comece a executar. Para sincronização, é melhor usar outros mecanismos que veremos a seguir.



Canais (Channels): transferência de dados entre goroutines



Canais são "tubos" tipados através dos quais as goroutines podem trocar dados. Um canal é criado com a função make e o operador chan. Os dados são enviados para o canal com o operador <- e recebidos dele também com <-, mas à esquerda do canal.



Vejamos um exemplo com canal bufferizado e não bufferizado:



package main

import "fmt"

func main() { // Canal não bufferizado (tamanho 0) ch := make(chan string) go func() { ch <- "Mensagem da goroutine" // Envia dados }() msg := <-ch // Recebe dados (bloqueia até chegar a mensagem) fmt.Println(msg) // Canal bufferizado (tamanho 2) bufferedCh := make(chan int, 2) bufferedCh <- 10 bufferedCh <- 20 fmt.Println(<-bufferedCh) // 10 fmt.Println(<-bufferedCh) // 20}


Importante: Um canal não bufferizado bloqueia o remetente até que o destinatário receba os dados. Um canal bufferizado bloqueia o remetente apenas quando o buffer está cheio.



Select: multiplexação de canais



O operador select permite que uma goroutine aguarde vários canais ao mesmo tempo e processe aquele que estiver pronto primeiro. É análogo ao switch, mas para canais. select é uma ferramenta poderosa para criar timeouts, cancelar operações e fazer verificações não bloqueantes.



package main

import ( "fmt" "time")

func main() { ch1 := make(chan string) ch2 := make(chan string) // Goroutine 1: envia dados após 1 segundo go func() { time.Sleep(1 * time.Second) ch1 <- "Dados do canal 1" }() // Goroutine 2: envia dados após 2 segundos go func() { time.Sleep(2 * time.Second) ch2 <- "Dados do canal 2" }() select { case msg1 := <-ch1: fmt.Println("Recebido:", msg1) case msg2 := <-ch2: fmt.Println("Recebido:", msg2) case <-time.After(500 * time.Millisecond): fmt.Println("Timeout! Nenhum canal respondeu em 500 ms") }}


Neste exemplo, o select será acionado pelo timeout, pois nenhum canal está pronto em 500 ms. Se removêssemos o timeout, o programa aguardaria o primeiro canal pronto.

Blogs

Book Recommendations