Historia de la pregunta:
Desde el principio, el lenguaje Go ha proporcionado el paquete time, dentro del cual se encuentran las funciones principales para manejar el tiempo: time.Sleep y time.After. A diferencia de los lenguajes con sueño del sistema (System.sleep), Go implementa temporizadores asincrónicos a través de sus primitivas, lo que es importante para el trabajo multihilo.
Problema:
A menudo, los desarrolladores utilizan incorrectamente time.Sleep para implementar pausas entre tareas, lo cual es indeseable en programas concurrentes. En la paradigma de Go, es más correcto gestionar la espera de eventos a través de canales y time.After para la integración con select/canales.
Solución:
time.Sleep(d) bloquea la gorutina actual durante d tiempo, es un «sueño» directo. time.After(d) devuelve un canal en el que aparecerá un evento de tiempo después de d. Esta última opción es mucho más flexible en select de canales, conveniente para esperas interrumpibles y tiempos de espera.
Ejemplo de código:
ch := make(chan struct{}) go func() { time.Sleep(2 * time.Second) ch <- struct{}{} }() select { case <-ch: fmt.Println("hecho") case <-time.After(1 * time.Second): fmt.Println("tiempo de espera") }
Características clave:
¿Se puede usar time.Sleep para bloquear la ejecución de todo el programa?
No, time.Sleep solo «duerme» una gorutina, las demás continúan trabajando.
¿Puede time.After causar una fuga de memoria si el canal no se lee?
Sí, el temporizador permanece hasta que el valor se lee; si no hay lectura, el recolector de basura no eliminará el objeto.
Ejemplo de código:
func leak() { for { _ = time.After(time.Hour) } }
¿Cómo cancelar correctamente la espera de time.After si no se recibe el evento?
Es mejor usar time.Timer y detenerlo manualmente si se necesita finalizar la espera antes de tiempo:
t := time.NewTimer(time.Minute) if done { t.Stop() }
La gorutina espera una señal de trabajo, y en caso de tiempo de espera hace lo siguiente:
time.Sleep(10*time.Second) doSomething()
Pros:
Contras:
El código se construye a través de select y time.After:
select { case <-workSignal: // Ejecutar case <-time.After(10 * time.Second): // Hacer por tiempo de espera }
Pros:
Contras: