Historia de la pregunta:
Una fuga de goroutines es una situación en la que una goroutine sigue existiendo y permanece en memoria, aunque en realidad "ha perdido su propósito" (los cálculos han terminado, los datos no son necesarios, pero no hay condición de salida). Es similar a las fugas de memoria, pero para los hilos de ejecución. Esto es crítico para Go, ya que una gran carga puede llevar al agotamiento de recursos.
Problema:
A diferencia de otros lenguajes, donde el control directo de los hilos a menudo conduce a su cierre manual, en Go las goroutines se inician fácilmente, pero no siempre se terminan correctamente. Un error común: la lógica principal ha terminado, pero la goroutine está "congelada": espera datos de un canal cerrado o no espera ninguna señal.
Solución:
Para prevenir fugas, se utilizan construcciones de control: contexto, cierre de canales, variables de señal. Es importante diseñar de antemano las rutas de salida de cada goroutine, utilizar defer para limpieza. Ejemplo:
func worker(ctx context.Context, jobs <-chan int, results chan<- int) { for { select { case <-ctx.Done(): return case job, ok := <-jobs: if !ok { return } results <- job * 2 } } }
Características clave:
¿Se puede simplemente cerrar el canal para detener una goroutine?
No siempre. Si en el select hay otros cases o no se verifica el cierre a través de ok, la goroutine puede quedarse "colgada".
val, ok := <-ch if !ok { return } // Así es más correcto
¿Qué pasará si olvido manejar context.Done en el select?
La goroutine nunca sabrá que se ha producido una cancelación: permanecerá "eterna". Este es un camino directo hacia una fuga.
¿Se puede detectar una fuga usando el runtime de Go?
No hay una herramienta estándar para rastrear fugas. Es necesario monitorear la cantidad de goroutines activas a través de runtime.NumGoroutine o utilizar detectores de fugas de bibliotecas de terceros.
En un sistema de envío de notificaciones push, se lanzan goroutines para cada mensaje entrante, pero se olvidan de detenerlas al cancelar el contexto o cerrar el canal: cientos de goroutines "muertas" permanecen en memoria.
Ventajas:
Desventajas:
El trabajo de la goroutine se controla a través del contexto, a nivel de lógica empresarial se verifica la salida del select, después de un envío/ procesamiento exitoso, el canal se cierra.
Ventajas:
Desventajas: