Contenido del curso
Fundamentos de Go
Estructuras de Datos y Funciones
- 8

Sentencia switch en Go con ejemplos reales
07:16 min - 9

Arreglos en Go: fijos e inferidos
06:55 min - 10

Creación y uso de slices dinámicos en Go
08:25 min - 11

Mapas en Go: creación, acceso y manipulación de datos clave-valor
09:37 min - 12

Cómo crear y usar funciones personalizadas en Go
07:09 min - 13

Retorno de múltiples valores en Go
07:43 min - 14

Funciones variadic en Go con tres puntos
07:10 min - 15

Funciones recursivas en Go con Fibonacci
06:11 min - 16

Punteros en Go para optimizar rendimiento del sistema
05:19 min - 17

Runas en Go: bytes vs caracteres reales
06:40 min - 18

Declaración y uso de estructuras de datos en Go
09:06 min - 19

Implementación de enumeradores en Go para controlar estados
09:32 min
Manejo de Errores y Concurrencia
Buenas Prácticas en Go
Timeouts en goroutines con time.After
Resumen
Cuando trabajas con goroutines y channels en Go, existe un riesgo silencioso: que una goroutine se quede procesando para siempre. Aquí entran los timeouts, una técnica que te permite definir cuánto tiempo esperar antes de cortar la espera y seguir con tu aplicación.
¿Por qué necesitas timeouts en goroutines y channels?
Imagina que lanzas una goroutine que envía su resultado a un channel, y un select espera ese resultado para continuar. Si algo falla (mala conexión, datos mal estructurados, un proceso que nunca termina) el channel mantiene su ciclo de vida activo y el select queda bloqueado.
Eso significa una aplicación colgada y un usuario frustrado esperando una respuesta que nunca llega. Los timeouts existen justamente para cortar ese hilo cuando excede el tiempo razonable.
¿Qué es un timeout en Go? Es un tiempo máximo de espera que defines para que una goroutine entregue su resultado a través de un channel. Si lo excede, tu programa toma otro camino en lugar de quedarse bloqueado.
¿Cómo implementar un timeout con time.After y select?
La pieza clave es el método time.After, que devuelve un channel después del tiempo que tú decidas. Combinado con select, te permite competir entre dos resultados: el de tu goroutine o el del temporizador.
El flujo básico es así:
- Creas un channel donde la goroutine enviará su resultado.
- Dentro de la goroutine, simulas o ejecutas un proceso que toma cierto tiempo.
- Usas
selectcon doscase: uno para recibir del channel y otro paratime.After. - El que llegue primero es el que se ejecuta.
Ejemplo práctico con time.Sleep y time.After
En la demostración [00:53] se crea una carpeta timeouts con un archivo main.go, importando fmt y time. Dentro de main se define un channel de tipo string con capacidad para un elemento, y una goroutine que fuerza una espera de dos segundos con time.Sleep antes de enviar el resultado al channel.
go package main
import ( "fmt" "time" )
func main() { contador1 := make(chan string, 1)
go func() { time.Sleep(2 * time.Second) contador1 <- "resultado 1" }() select { case resultado := <-contador1: fmt.Println("recibido", resultado) case <-time.After(1 * time.Second): fmt.Println("timeout") }
}
Aquí está la lógica: si la goroutine tarda dos segundos pero time.After solo da uno, el timeout gana. Al ejecutar go run main.go, la salida es timeout. La goroutine ni siquiera tiene oportunidad de entregar su resultado [03:13].
¿Qué pasa si el tiempo de espera es mayor al de la goroutine?
Si cambias time.After(1 * time.Second) por time.After(3 * time.Second), la goroutine ahora sí tiene margen para terminar su trabajo en sus dos segundos originales. La salida cambia a recibido resultado 1 [03:30].
Ese pequeño ajuste muestra cómo controlas con precisión cuánto estás dispuesto a esperar antes de tomar otra ruta.
¿Cómo aplicar timeouts en múltiples goroutines simultáneas?
Puedes replicar la misma estructura para varias goroutines y cada una tendrá su propio comportamiento según el tiempo que tarde. En la demostración [04:07] se agrega un contador2 con un tiempo distinto, dejando que una caiga en timeout y la otra entregue su resultado correctamente.
La ventaja es clara:
- Cada goroutine se evalúa de forma independiente.
- Detectas rápidamente cuál proceso es lento o problemático.
- Tu aplicación nunca depende del peor caso de un proceso colgado.
¿Cuándo debo usar timeouts con channels? Siempre que uses channels para recibir resultados de goroutines. Sin un timeout, tu aplicación puede esperar indefinidamente un resultado que nunca llegará.
¿Qué buenas prácticas seguir al usar timeouts en Go?
La recomendación final es directa: implementa timeouts en todo momento que uses channels. Sin ellos, podrías estar esperando un resultado que nunca llegará, provocando que tu aplicación colapse o que el usuario abandone por falta de respuesta.
Algunos puntos a tener en cuenta:
- Define tiempos realistas según el tipo de operación (red, base de datos, cálculo).
- Maneja el caso del timeout con un mensaje claro o una acción alternativa.
- Combina
selectcontime.Aftercomo patrón estándar para procesos asíncronos.
Con esta técnica coronas la implementación de un select robusto en Go. ¿En qué parte de tu código crees que un timeout te habría salvado de un bloqueo? Cuéntame tu caso en los comentarios.