0Pricing
Go Academy · Lección

Channels sin búfer

Transferencia síncrona entre goroutines

Channels sin búfer es una lección gratuita de Go Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Go Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Go Academy incluye 4 lecciones en total.

¿Qué es un canal?

Un canal es un conducto con tipo para comunicarse entre goroutines. Los canales siguen el principio de Go: No se comunique compartiendo memoria; comparta memoria comunicándose.

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 los canales sin búfer

Un canal sin búfer no tiene capacidad. Un envío se bloquea hasta que hay un receptor preparado, y una recepción se bloquea hasta que un emisor envía. Esto proporciona una entrega síncrona garantizada:

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
}

El canal como mecanismo de sincronización

Los canales sin búfer sincronizan las goroutines; úselos como señal de que el trabajo ha terminado:

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
}

Cerrar un canal

El emisor cierra un canal con close(ch) para indicar que no se enviarán más valores. Los receptores detectan el cierre mediante la forma de dos 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")
}

Recepción de dos valores

La recepción de dos valores, v, ok := <-ch, indica si el canal sigue abierto:

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 en un canal cerrado provoca un pánico

Enviar a un canal cerrado provoca un pánico. Solo el emisor debe cerrar un canal; nunca el receptor:

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
}

Canales direccionales

Restrinja los canales a solo envío (chan<- T) o solo recepción (<-chan T) en las firmas de las funciones para mejorar la claridad y la seguridad:

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)
}

Ping-pong entre goroutines y canales

Dos goroutines que se pasan un mensaje de un lado a otro mediante canales: una demostración clásica de sincronización:

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")
}

Los canales nil se bloquean para siempre

Recibir de un canal nil o enviarle un valor se bloquea para siempre. A veces esto se usa intencionadamente en instrucciones 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)
    }
}

Cuándo usar canales sin búfer

Use canales sin búfer cuando:

  • Necesite una entrega síncrona garantizada
  • La goroutine deba confirmar la recepción antes de que el emisor continúe
  • Implemente semáforos o back-pressure
  • Use pipelines en los que cada etapa deba procesar un elemento cada vez

Comprobación rápida

¿Qué ocurre cuando envía en un canal sin búfer que no tiene ningún receptor preparado?

Recapitulación: canales sin búfer

Resumen:

  • Cree canales con make(chan T): capacidad cero
  • El envío se bloquea hasta que el receptor está preparado; la recepción se bloquea hasta que el emisor envía
  • Solo el emisor debe cerrar un canal
  • range ch itera hasta que el canal se cierra
  • Recepción de dos valores: v, ok := <-ch
  • Use tipos direccionales para mejorar la claridad: chan<- y <-chan

Preguntas frecuentes

¿La lección «Channels sin búfer» es gratis?

Sí — el texto completo de «Channels sin búfer» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Go Academy, actualiza a CoddyKit PRO. El curso de Go Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Channels sin búfer»?

Transferencia síncrona entre goroutines Practicas Go Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Go Academy?

No se requiere experiencia previa. Go Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Channels sin búfer»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Go Academy?

Sí. Cada lección de Go Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Lanzamiento de goroutines
  2. Channels sin búfer
  3. Channels con búfer
  4. Dirección de channels y patrones de pipelines
← Volver a Go Academy