Lecciones del módulo (1/5)
Gorutinas: paralelismo ligero
Una gorrutina es una unidad de ejecución concurrente administrada por Go
tiempo de ejecución. Lanzas uno con la palabra clave go delante de una función
llamar:
go greet("Anna") // chiamata a funzione esistente
go func() { // funzione anonima
fmt.Println("hi")
}()La declaración go devuelve inmediatamente: la rutina comienza en
paralelo y la persona que llama continúa.
Por qué son "ligeros"
- Pila inicial ~2KB (crece dinámicamente, hasta cientos de MB si es necesario).
- Multiplexado en una pequeña cantidad de subprocesos del sistema operativo mediante el tiempo de ejecución (
GOMAXPROCS). - Miles/millones de gorutinas son rutinarias; con subprocesos del sistema operativo serían imposibles.
Conceptualmente es "disparar y olvidar simultáneamente", pero con todas las
herramientas idiomáticas para coordinar (canales, sync.WaitGroup,
CÓDIGOPH1).
principal no espera
func main() {
go func() { fmt.Println("ciao dalla goroutine") }()
// main esce subito: niente garanzia che la goroutine completi
}Cuando main regresa, el proceso termina: las gorutinas no obtienen
para "terminar su trabajo", simplemente son asesinados junto con el
proceso. Se requiere sincronización explícita.
Sincronización: una vista previa
Las tres herramientas que verás en las próximas lecciones:
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
work()
done <- struct{}{}
}()
<-done // attendi
// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()
// 3) context: cancellazione/timeout propagatiEl error "clásico" de cierre en bucle
Hasta Go 1.21, este era un problema frecuente:
for i := 0; i < 3; i++ {
go func() { fmt.Println(i) }() // stampa "3 3 3" su versioni vecchie
}Desde Go 1.22 la variable for se crea recientemente en cada
iteración, por lo que el error se soluciona de forma predeterminada. En bases de código más antiguas, podrás
Todavía veo el patrón de corrección:
for i := 0; i < 3; i++ {
i := i // shadow esplicito
go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
go func(n int) { fmt.Println(n) }(i)
}Goroutine! = Hilo del sistema operativo
| Aspecto | Gorrutina | Hilo del sistema operativo |
|---|---|---|
| Pila inicial | ~2 KB | 1–8 MB (asignado al inicio) |
| Creación | nanosegundos | microsegundos |
| Programación | Ir en tiempo de ejecución (cooperativo) | kernel (preventivo) |
| Conteo práctico | 100K+ | unos cuantos miles |
Un único subproceso del sistema operativo puede albergar muchas rutinas. El tiempo de ejecución se mueve gorutinas a través de subprocesos cuando sea necesario.
Pruébalo
Inicie la función de bienvenida como una rutina y espere 100 ms con el tiempo. Duerma antes de salir de principal.
Mostrar pista
`go` delante de una llamada de función lanza la rutina.
Solución disponible después de 3 intentos
Inicie una función anónima como una rutina que imprima "hola".
Mostrar pista
Se llama a una función anónima con un `()` final: `go func(){...}()`.
Solución disponible después de 3 intentos
¿Qué sucede si `main` sale antes de que se complete una rutina?
func main() {
go work()
// main ritorna immediatamente
}Resumen
go f()lanza f() al mismo tiempo; regresa inmediatamente.- Goroutine = ~2 KB inicial, multiplexado en algunos subprocesos del sistema operativo.
mainno espera: necesita sincronización (canal/Grupo de espera/contexto).time.Sleepes sólo didáctico, nunca para sincronización en producción.- Desde Go 1.22, la variable
fores "nueva" en cada iteración (no más errores "3 3 3").