0Pricing
Go Academy · Aula

Canais sem buffer

Transferência síncrona entre goroutines

Canais sem buffer é uma aula grátis de Go Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Go Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Go Academy inclui 4 aulas no total.

O que é um canal?

Um canal é um meio tipado de comunicação entre goroutines. Os canais seguem o princípio do Go: Não se comunique compartilhando memória; compartilhe memória comunicando-se.

package main
import "fmt"

func main() {
    ch := make(chan int)   // unbuffered int channel

    go func() {
        ch <- 42  // send: blocks until someone receives
    }()

    v := <-ch  // receive: blocks until someone sends
    fmt.Println(v) // 42
}

Semântica de canais sem buffer

Um canal sem buffer não tem capacidade. Um envio fica bloqueado até que um receptor esteja pronto, e um recebimento fica bloqueado até que um remetente envie. Isso garante uma transferência síncrona:

package main
import "fmt"

func double(in <-chan int, out chan<- int) {
    for v := range in {
        out <- v * 2
    }
    close(out)
}

func main() {
    in := make(chan int)
    out := make(chan int)
    go double(in, out)
    go func() { in <- 3; in <- 5; close(in) }()
    for v := range out { fmt.Println(v) }
    // 6
    // 10
}

Canal como mecanismo de sincronização

Canais sem buffer sincronizam goroutines — use-os como sinal de que o trabalho terminou:

package main
import "fmt"

func compute(result chan<- int) {
    sum := 0
    for i := 1; i <= 100; i++ { sum += i }
    result <- sum
}

func main() {
    ch := make(chan int)
    go compute(ch)
    fmt.Println("Result:", <-ch) // blocks until compute sends
}

Fechando um canal

O sender fecha um canal com close(ch) para sinalizar que nenhum valor adicional será enviado. Receivers detectam o fechamento usando a forma de dois valores:

package main
import "fmt"

func generate(ch chan<- int, max int) {
    for i := 0; i < max; i++ {
        ch <- i
    }
    close(ch)  // signal done
}

func main() {
    ch := make(chan int)
    go generate(ch, 5)

    for v := range ch {  // range detects close automatically
        fmt.Println(v)
    }
    fmt.Println("channel closed")
}

Recebimento de dois valores

O recebimento de dois valores v, ok := <-ch informa se o canal ainda está aberto:

package main
import "fmt"

func main() {
    ch := make(chan string, 1)
    ch <- "hello"
    close(ch)

    v1, ok1 := <-ch
    fmt.Println(v1, ok1)  // hello true

    v2, ok2 := <-ch
    fmt.Println(v2, ok2)  // "" false — channel closed
}

Enviar para um canal fechado causa pânico

Enviar para um canal fechado causa pânico. Somente o sender deve fechar um canal — nunca o receiver:

package main
import "fmt"

func main() {
    ch := make(chan int)
    close(ch)

    // Receiving from closed channel returns zero value
    v, ok := <-ch
    fmt.Println(v, ok)  // 0 false

    // Sending to closed channel panics:
    defer func() { recover() }()
    ch <- 1  // panic: send on closed channel
}

Canais direcionais

Restrinja canais a somente envio (chan<- T) ou somente recebimento (<-chan T) nas assinaturas de função, para obter clareza e segurança:

package main
import "fmt"

func producer(out chan<- int) {  // send-only
    for i := 0; i < 3; i++ { out <- i }
    close(out)
}

func consumer(in <-chan int) {   // receive-only
    for v := range in { fmt.Println(v) }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

Pingue-pongue entre goroutines e canais

Duas goroutines passam uma mensagem de um lado para o outro por meio de canais — uma demonstração clássica de sincronização:

package main
import "fmt"

func ping(ping, pong chan struct{}) {
    for i := 0; i < 3; i++ {
        <-ping
        fmt.Println("ping")
        pong <- struct{}{}
    }
}

func main() {
    ping := make(chan struct{})
    pong := make(chan struct{})
    go func() { for { <-pong; fmt.Println("pong"); ping <- struct{}{} } }()
    go func() { for i := 0; i < 3; i++ { ping <- struct{}{}; <-pong } }()
    // Simplified version:
    fmt.Println("channels enable structured communication")
}

Canais nil bloqueiam para sempre

Receber de um canal nil ou enviar para ele bloqueia para sempre. Às vezes, isso é usado intencionalmente em instruções select:

package main
import "fmt"

func main() {
    var ch chan int  // nil channel
    fmt.Println(ch == nil) // true

    // select with nil channel — that case is never selected
    active := make(chan int, 1)
    active <- 42
    select {
    case v := <-ch:      // never selected (nil)
        fmt.Println(v)
    case v := <-active:  // selected
        fmt.Println("got:", v)
    }
}

Quando usar canais sem buffer

Use canais sem buffer quando:

  • Precisar de uma transferência síncrona garantida
  • A goroutine precisar confirmar o recebimento antes que o sender continue
  • Estiver implementando semáforos ou contrapressão
  • Estiver implementando canalizações em que cada etapa deve processar um item por vez

Verificação rápida

O que acontece quando se envia por um canal sem buffer sem que haja um receptor pronto?

Revisão: canais sem buffer

Resumo:

  • Crie com make(chan T) — capacidade zero
  • O envio fica bloqueado até que um receptor esteja pronto; o recebimento fica bloqueado até que um sender envie
  • Somente o sender deve fechar um canal
  • range ch itera até o fechamento
  • Recebimento de dois valores: v, ok := <-ch
  • Use tipos direcionais para obter clareza: chan<- e <-chan

Perguntas Frequentes

A aula “Canais sem buffer” é grátis?

Sim — o texto completo de “Canais sem buffer” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Go Academy, atualize para CoddyKit PRO. O curso de Go Academy inclui 4 aulas no total.

O que vou aprender em “Canais sem buffer”?

Transferência síncrona entre goroutines Você pratica Go Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Go Academy?

Nenhuma experiência prévia é necessária. Go Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Canais sem buffer”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Go Academy?

Sim. Cada aula de Go Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Iniciando goroutines
  2. Canais sem buffer
  3. Canais com buffer
  4. Direção de canais e padrões de pipeline
← Voltar para Go Academy