Rutinas en Golang
Tags: go, programming, concurrency, threads
Published: 2023-02-10 06:13:20

## Introducción
La principal ventaja de Golang, es la facilidad con la que se puede manejar multithread virtuales, a diferencia de otros lenguajes como Java, que incorpora la interfaz `Thread` o Javascript que lo hace a partir de las promesas.

## Que es un thread?

> En sistemas operativos, un hilo o hebra (del inglés thread), proceso ligero o subproceso es una secuencia de tareas encadenadas muy pequeña que puede ser ejecutada por un sistema operativo. (Wikipedia)

Estos procesos, suelen ser ejecutados por **varios cores de un microprocesador**, por lo que si se tiene un procesador multicore, estos procesos pueden ser ejecutados por más de un core. Los sistemas operativos proveen un scheduler que lanza y administra estos hilos de ejecución, y los gestiona para evitar [condiciones de carrera](https://en.wikipedia.org/wiki/Race_condition).

## Go Rutinas == Threads ligeros
Las rutinas de Golang suelen ser threads ligeros, ejecutados por **núcleos virtuales** generados por el runtime de Golang.

### Paralelismo vs Concurrencia
Por que en Golang se usa la **concurrencia** y no el paralelismo? La principal diferencia es que 2 tareas son paralelas cuando se ejecutan al mismo tiempo, estas tareas son ejecutadas con 2 cores de un mismo procesador físico, por lo que es posible poder ejecutar 2 instrucciones al mismo tiempo.
Sin embargo, cuando una aplicación es concurrente en Go, el runtime de Go genera thread virtuales dentro de un mismo core, por lo que las instrucciones de los 2 thread virtuales se ejecutan en el mismo core, pero entrecruzadas, por lo que termina siendo un paso a paso.

Ejemplo:

```
Thread 1      | Thread 2
--------------|--------------
Instrucción 1 | 
Instrucción 2 | 
              | Instrucción 3
Instrucción 4 | 
              | Instrucción 5
...
```

### Scheduler (o planificador del SO)
El scheduler es la parte del sistema operativo que se encarga de seleccionar a qué proceso se asigna el procesador y durante cuánto tiempo.
Algunas de sus tareas que podemos enumerar son:

- Llevar el control de estado de cada proceso, decidiendo que proceso utilizará el procesador y cuanto tiempo lo hará. Esto evitará que haya ciertos procesos que utilicen todo el procesador.
- Establecer el contexto de ejecución a la vez que se le asigna un proceso al procesador.
- Por último, quitará el procesador del proceso, guardando el contexto para una ejecución posterior. 

En pocas palabras, el scheduler del SO toma la carga del trabajo y la reparte sobre los recursos que posee.

### Sistema Operativo vs Go Runtime
El planificador del sistema operativo, es capaz de ejecutar procesos en paralelo, es decir en distintos cores del procesador, mientras que el Go Runtime crea hilos virtuales para poder ejecutar los comandos de forma concurrente, uno detrás del otro, es decir cada hilo de ejecución ejecutara sus instrucciones en el mismo core del procesador que la otra. 
En este caso, encontramos que el Runtime de Go utiliza el scheduler del SO.

## Ejemplo
Cómo no todo es teoría, acá veamos un ejemplo práctico:

```golang
package main

import (
   "fmt"
   "time"
)

func say(word string) {
   for j := 0; j < 5; j++ {
      time.Sleep(time.Millisecond * 100)
      fmt.Println(word)
   }
}

func main() {
   go say("Hello")
   say("world")
}
```
En este caso vemos que nuestro hilo principal ejecutará el `say("world")` mientras que nuestra rutina ejecutará el `say("hello")`. Si ejecutamos estas instrucciones nos daremos cuenta del resultado:

![Ejecución de una Go Rutina](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrnhe0zv262lss5ol8ur.png)

[Link al ejemplo](https://go.dev/play/p/ha2QT2QFtPC)

## Conclusión
Por último, dejo algunas conclusiones:
* **Las Go rutinas son más ligeras que threads**: Esto se debe a que las go rutinas ocupan un stack space de 2 KB, lo cual es extremadamente más compacto que los 2 MB que implican el tamaño fijo del stack space del OS Thread.
* **No abusar de las rutinas**: Como todo en exceso es malo, llegar a tener muchas rutinas puede llegar a serlo. Es importante tener un control de las mismas, ya que en algún momento, si deseamos cancelar la ejecución de nuestro programa, podemos llegar a encontrarnos con varias rutinas ejecutándose y ocupando recursos que deseamos, estén libres.
* **Se pueden controlar con Go Tool Trace**: De la mano con el punto anterior, podemos utilizar el Go Tool Trace para poder controlar nuestras rutinas. Pero esto lo hablaremos en algún post posterior.