Go destaca frente a Java, Python o Erlang por simplificar la concurrencia a una sola palabra clave: go. Una goroutine es una función que el runtime de Go ejecuta en paralelo con el resto del programa, sin que el desarrollador tenga que crear hilos, dimensionar pools ni instalar librerías.
El artículo explica tres pilares. Primero, cómo se inicia una goroutine y por qué main nunca espera a las goroutines que lanza: al retornar main, el proceso termina y se pierden los resultados pendientes. La solución correcta no es time.Sleep, sino sync.WaitGroup, que mantiene un contador de trabajos pendientes y bloquea main hasta que llega a cero.
Segundo, la diferencia entre goroutines y hilos del sistema operativo. Una goroutine arranca con una pila mínima de 2 KB que el runtime puede crecer, frente a los 8 MB que reserva por defecto un hilo de Linux. Su creación no requiere una llamada al sistema, y el cambio de contexto ocurre dentro del propio proceso gracias al planificador m:n de Go, que reparte m goroutines entre n hilos del sistema.
Tercero, el papel de GOMAXPROCS, el límite dinámico que controla cuántos hilos pueden ejecutar código Go simultáneamente. Suele coincidir con NumCPU, pero desde Go 1.25 dentro de un contenedor con límite de CPU el runtime respeta la cuota del contenedor en lugar del número total de núcleos del host. Con GOMAXPROCS(1) las goroutines se intercalan de forma ordenada; al subir el límite, la salida se mezcla porque varias goroutines escriben a la vez.
