El caso por defecto en una declaración select se comporta casi como bloqueante.
He notado un comportamiento extraño que no es del todo obvio al usar una sentencia select dentro de un loop, por ejemplo, si tengo:
package main
import (
"fmt"
"time"
)
func main() {
done := make(chan bool)
go func() {
fmt.Println("here we go")
for {
select {
case <-done:
fmt.Println("Bye")
return
default:
fmt.Println("esto debería continuar imprimiéndose")
}
fmt.Println("loop continues")
}
}()
time.Sleep(2 * time.Second)
done <- true
}
Yo asumiría que el caso default solo se imprimirá por no más de 2 segundos, sin embargo, este no es el caso, por lo menos en mi CPU dura alrededor de 10 segundos antes de ver el mensaje de Bye
.
Sin embargo, si agrego time.Sleep(1 * time.Second)
justo después de “loop continues” Está más o menos en sincronía con el sueño de 2 segundos antes de done <- true
.
Dado esto, mi suposición es que las llamadas de impresión se están apilando y el tiempo prolongado de finalización se debe a que la pila de llamadas tarda más tiempo en pasar. ¿Es esta una descripción correcta de lo que está sucediendo? ¿O me falta algo más obvio?
Edit: Para poner mi hipótesis a prueba, hice esto y ahora funciona como se esperaba, tarda 2 segundos en finalizar el programa:
go func() {
fmt.Println("here we go")
for {
select {
case <-done:
fmt.Println("Bye")
return
default:
}
}
}()
davy.ai
Parece que tu hipótesis es correcta. Cuando la instrucción
select
se encuentra dentro de un bucle y se activa el casodefault
, las llamadas afmt.Println
se amontonan y el programa tarda más en completarse.Agregar un
time.Sleep(1 * time.Second)
justo después de “el bucle continúa” parece funcionar porque le da tiempo a las llamadas afmt.Println
para completarse antes de que continúe el bucle.Alternativamente, como has mostrado en tu edición, eliminar las llamadas a
fmt.Println
dentro del bucle y dejarlas solo dentro del casodone
donde se recibe el canal también funciona y asegura que el programa finalice de manera oportuna.