Go
Tutorial Go: Goroutines y concurrencia básica
Go goroutines y concurrencia básica. Descubre cómo manejar ejecuciones concurrentes y sincronización con WaitGroups para mejorar el rendimiento.
Aprende Go GRATIS y certifícateCómo crear y manejar Goroutines.
En Go, las goroutines son funciones o métodos que se ejecutan de manera concurrente con otras goroutines en un programa. Para crear una goroutine, se utiliza la palabra clave go
seguida de la invocación de la función. Este mecanismo permite que el programa continúe su ejecución sin esperar a que la función termine, facilitando la concurrencia.
Para iniciar una goroutine, simplemente anteponemos go
a la llamada de una función. Por ejemplo, si tenemos una función procesarDatos()
, podemos convertirla en una goroutine de la siguiente manera:
func procesarDatos() {
// Lógica de procesamiento
}
func main() {
go procesarDatos()
// Otras operaciones
}
En este ejemplo, procesarDatos()
se ejecutará concurrentemente con el resto del código en main()
. Es importante destacar que las goroutines comparten el mismo espacio de direcciones, lo cual puede dar lugar a condiciones de carrera si no se gestionan adecuadamente los accesos concurrentes a las variables compartidas.
Las goroutines son ligeras y gestionadas por el runtime de Go, lo que significa que no tienes que preocuparse por la creación y gestión manual de hilos del sistema operativo. Esto permite que cientos de miles de goroutines puedan ejecutarse simultáneamente en un sistema.
Un aspecto crucial al manejar goroutines es asegurarse de que el programa principal no finalice antes de que todas las goroutines hayan completado su ejecución. De lo contrario, las goroutines podrían ser terminadas abruptamente. Para gestionar el ciclo de vida de las goroutines, es común utilizar mecanismos de sincronización, que son esenciales para evitar problemas de ejecución.
Es fundamental tener en cuenta que las goroutines no tienen una relación directa con los hilos del sistema operativo; el scheduler de Go asigna goroutines a un número fijo de hilos del sistema, permitiendo una gestión eficiente de los recursos.
El uso de goroutines es una técnica poderosa para mejorar el rendimiento de las aplicaciones, especialmente en tareas intensivas en I/O o que pueden ejecutarse de forma independiente. Sin embargo, es necesario diseñar cuidadosamente la arquitectura de la aplicación para evitar problemas de sincronización y asegurar que las goroutines se gestionen de manera eficiente.
Uso de WaitGroups para gestionar ciclos de vida de las Goroutines.
En la programación concurrente con Go, es crucial asegurarse de que las goroutines completen su ejecución antes de que el programa principal termine. Para gestionar esto, Go proporciona el paquete sync
, que incluye el tipo WaitGroup
. Un WaitGroup
permite esperar a que un conjunto de goroutines finalice su ejecución.
Un WaitGroup
actúa como un contador de goroutines. Se incrementa con cada goroutine que se lanza y se decrementa cuando una goroutine finaliza. El programa principal, o cualquier otra goroutine, puede llamar a Wait()
en el WaitGroup
para bloquearse hasta que el contador llegue a cero, indicando que todas las goroutines han terminado.
Para utilizar un WaitGroup
, sigue los siguientes pasos:
Declarar un WaitGroup: Inicializa una variable del tipo sync.WaitGroup
.
Añadir al contador: Antes de lanzar una goroutine, incrementa el contador del WaitGroup
utilizando el método Add(n)
, donde n
es el número de goroutines que vas a lanzar.
Ejecutar las goroutines: Dentro de cada goroutine lanzada, al finalizar su trabajo, llama al método Done()
del WaitGroup
para decrementar el contador.
Esperar a que terminen: En el punto del programa donde necesitas esperar a que todas las goroutines terminen, llama al método Wait()
del WaitGroup
.
Ejemplo práctico de cómo utilizar un WaitGroup
para gestionar el ciclo de vida de las goroutines:
package main
import (
"fmt"
"sync"
)
func procesar(id int, wg *sync.WaitGroup) {
defer wg.Done() // Decrementa el contador del WaitGroup cuando la goroutine termina
fmt.Printf("Goroutine %d en ejecución\n", id)
// Simula trabajo con una goroutine
}
func main() {
var wg sync.WaitGroup
numGoroutines := 5
for i := 0; i < numGoroutines; i++ {
wg.Add(1) // Incrementa el contador del WaitGroup
go procesar(i, &wg)
}
wg.Wait() // Espera a que todas las goroutines llamen a Done()
fmt.Println("Todas las goroutines han finalizado")
}
En este ejemplo, el WaitGroup
se utiliza para gestionar cinco goroutines. El método Add(1)
se llama antes de lanzar cada goroutine, y el método Done()
se llama al final de cada goroutine para indicar que ha terminado su trabajo. Finalmente, wg.Wait()
bloquea el programa principal hasta que todas las goroutines han completado su ejecución.
El uso de WaitGroup
es fundamental para asegurar la correcta finalización de las goroutines en aplicaciones concurrentes. Este enfoque evita que el programa principal termine prematuramente, lo cual podría provocar la terminación abrupta de las goroutines en ejecución.
Ejemplos de ejecución concurrente utilizando Goroutines.
En el contexto de la programación concurrente con Go, las goroutines se utilizan para ejecutar funciones de manera simultánea, lo que permite aprovechar mejor los recursos del sistema. Un aspecto esencial al trabajar con goroutines es entender cómo se ejecutan concurrentemente y cómo se puede observar su comportamiento. A continuación, se presentan ejemplos que ilustran cómo las goroutines permiten la ejecución concurrente de tareas.
Para demostrar la concurrencia, supongamos que tenemos una función imprimirNumeros
que imprime números del 1 al 5. Al ejecutar esta función como goroutine, podemos observar cómo se intercalan las salidas cuando se ejecutan múltiples instancias concurrentemente:
package main
import (
"fmt"
"time"
)
func imprimirNumeros(id int) {
for i := 1; i <= 5; i++ {
fmt.Printf("Goroutine %d: %d\n", id, i)
time.Sleep(100 * time.Millisecond) // Simula trabajo
}
}
func main() {
for i := 1; i <= 3; i++ {
go imprimirNumeros(i)
}
time.Sleep(1 * time.Second) // Espera para permitir que todas las goroutines terminen
}
En este ejemplo, se lanzan tres goroutines que ejecutan la función imprimirNumeros
. El uso de time.Sleep
dentro de la función simula una tarea que lleva tiempo, permitiendo observar cómo las goroutines se alternan en su ejecución. Concurrentemente, cada goroutine imprime sus números, lo que resulta en una salida donde los números de diferentes goroutines se mezclan.
Un punto clave al utilizar goroutines es que el programa principal debe esperar a que las goroutines concluyan su ejecución antes de terminar. Si no se gestiona adecuadamente, el programa principal podría finalizar antes de que las goroutines completen su tarea. En el ejemplo anterior, utilizamos time.Sleep
en main
para dar tiempo a las goroutines a finalizar, aunque en un entorno de producción se recomienda el uso de sync.WaitGroup
para una gestión más robusta.
Además, es fundamental tener en cuenta que las goroutines comparten el mismo espacio de memoria, lo que significa que pueden acceder a variables compartidas. Esto puede llevar a condiciones de carrera si no se sincronizan adecuadamente los accesos concurrentes. La correcta gestión de la concurrencia es esencial para evitar errores en la ejecución de programas concurrentes.
El uso de goroutines para ejecutar funciones de manera concurrente es una técnica eficaz para aumentar la eficiencia de las aplicaciones en Go, especialmente cuando se realizan tareas que no dependen unas de otras. Estos ejemplos ilustran la potencia de las goroutines al permitir que múltiples funciones se ejecuten al mismo tiempo, haciendo pleno uso del potencial de procesamiento del hardware disponible.
Ejercicios de esta lección Goroutines y concurrencia básica
Evalúa tus conocimientos de esta lección Goroutines y concurrencia básica con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Cadenas de texto y manipulación
Selectores y mutexes: concurrencia y exclusión
Agenda de contactos por consola
Composición de structs en lugar de herencia
Estructuras de control
Arrays y slices
Control de flujo y estructuras de bucle
Sistema API REST gestión de libros
Métodos con receptores por valor y por puntero
API REST con net/http
Generics
Evaluación Go
Métodos HTTP con net/http
Crear e invocar funciones
Operadores y expresiones
Polimorfismo a través de Interfaces
Manejo explícito de errores
Estructuras structs
Tipos de datos, variables y constantes
Introducción a Go
Canales y comunicación entre Goroutines
Condiciones de carrera
Punteros y referencias
Goroutines y concurrencia básica
Instalación Go primer programa
Errores personalizados y trazabilidad
Estructuras de datos Mapas
Cliente de API OpenWeatherMap clima
Todas las lecciones de Go
Accede a todas las lecciones de Go y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Go
Introducción Y Entorno
Instalación Y Primer Programa De Go
Introducción Y Entorno
Tipos De Datos, Variables Y Constantes
Sintaxis
Operadores Y Expresiones
Sintaxis
Cadenas De Texto Y Manipulación
Sintaxis
Estructuras De Control
Sintaxis
Control De Flujo Y Estructuras De Bucle
Sintaxis
Funciones
Sintaxis
Arrays Y Slices
Estructuras De Datos
Mapas
Estructuras De Datos
Punteros Y Referencias
Estructuras De Datos
Estructuras Structs
Programación Orientada A Objetos
Métodos Con Receptores Por Valor Y Por Puntero
Programación Orientada A Objetos
Polimorfismo A Través De Interfaces
Programación Orientada A Objetos
Composición De Structs En Lugar De Herencia
Programación Orientada A Objetos
Generics
Programación Orientada A Objetos
Manejo Explícito De Errores
Manejo De Errores Y Excepciones
Errores Personalizados Y Trazabilidad
Manejo De Errores Y Excepciones
Métodos Http Con Net/http
Comunicación Por Http
Api Rest Con Net/http
Comunicación Por Http
Goroutines Y Concurrencia Básica
Concurrencia Y Paralelismo
Canales Y Comunicación Entre Goroutines
Concurrencia Y Paralelismo
Condiciones De Carrera
Concurrencia Y Paralelismo
Selectores Y Mutexes Concurrencia Y Exclusión Mutua
Concurrencia Y Paralelismo
Evaluación Conocimientos Go
Evaluación
Certificados de superación de Go
Supera todos los ejercicios de programación del curso de Go y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender qué son las goroutines y su relación con los hilos del sistema.
- Aprender a implementar goroutines para ejecución concurrente en Go.
- Manejar el ciclo de vida de las goroutines utilizando WaitGroups.
- Identificar y evitar condiciones de carrera al compartir datos entre goroutines.
- Mejorar el rendimiento de aplicaciones mediante tareas concurrentes intensivas en I/O.