"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > GO: Concurrencia vs Paralelismo Para Tontos.

GO: Concurrencia vs Paralelismo Para Tontos.

Publicado el 2024-09-01
Navegar:936

Bienvenido a este post con un título un poco denigrante.
Pero, en este post quiero explicarte que son estas 2 características de la programación de una forma muy sencilla, en esta ocasión usando mi lenguaje de programación favorito GOLANG.

Imaginemos una cocina:

Cocinar un plato: Esto representa una tarea.
Un cocinero: Es un procesador.
Concurrencia:

Varios cocineros en la cocina: Cada uno preparando un plato diferente.
En Go: Cada cocinero sería una goroutine. Aunque la cocina (el procesador) solo tiene un horno, los cocineros pueden trabajar en sus platos de forma simultánea, pasando el tiempo en otras tareas mientras esperan que el horno esté disponible.
Paralelismo:

Varios hornos: Cada cocinero tiene su propio horno.
En Go: Si tenemos múltiples procesadores físicos, cada goroutine podría ejecutarse en un procesador diferente, cocinando varios platos al mismo tiempo de manera real.

¿Cuál es la diferencia?

Concurrencia: Las tareas se ejecutan de forma entrelazada, dando la ilusión de paralelismo, incluso en un solo procesador.
Paralelismo: Las tareas se ejecutan simultáneamente en múltiples procesadores, lo que acelera significativamente el proceso.

¿Cómo usarlos en Go?

Goroutines: Son como hilos ligeros. Para crear una goroutine, simplemente utilizamos la palabra clave go antes de una función:

GO: Concurrencia vs Paralelismo Para Tontos.

Veamos un ejemplo sobre como podemos usar goroutines en golang:

go func() {
    // Código que se ejecutará en una goroutine
}()

Canales: Son tuberías por las cuales las goroutines pueden comunicarse y sincronizarse.
Imagina que son tubos para pasar ingredientes entre los cocineros

ch := make(chan int)
go func() {
    ch 



Ejemplo práctico:

package main

import (
    "fmt"
    "time"
)

func worker(id int, c chan int) {
    for n := range c {
        fmt.Printf("Worker %d received %d\n", id, n)
        time.Sleep(time.Second)
    }
}

func main() {
    c := make(chan int)

    for i := 1; i 



La salida de este código sería

Worker 1 received 1
Worker 2 received 2
Worker 3 received 3
Worker 4 received 4
Worker 5 received 5
Worker 1 received 6
Worker 2 received 7
Worker 3 received 8
Worker 4 received 9
Worker 5 received 10

aunque aveces podría verse así

Worker 5 received 1
Worker 1 received 3
Worker 2 received 2
Worker 4 received 5
Worker 3 received 4
Worker 3 received 6
Worker 5 received 10
Worker 2 received 8
Worker 4 received 7
Worker 1 received 9

o así

Worker 5 received 1
Worker 1 received 2
Worker 2 received 3
Worker 3 received 4
Worker 4 received 5
Worker 1 received 6
Worker 2 received 7
Worker 3 received 8
Worker 5 received 9
Worker 4 received 10

¿Por qué la salida cambia cada vez que ejecuto el programa?

La razón principal por la que la salida del programa cambia en cada ejecución es debido a la naturaleza no determinista de la concurrencia.

Aquí hay un desglose de lo que está sucediendo:

Crear un canal: make(chan int) crea un canal de enteros. Este canal se utilizará para la comunicación entre las goroutines.

Iniciar goroutines: El bucle for i := 1; i La función worker recibe el ID y el canal.

Enviar valores al canal: El bucle for n := 1; n 1 al 10 al canal.

Cerrar el canal: La llamada close(c) cierra el canal, indicando que no se enviarán más valores.

Recibir valores del canal: Cada goroutine recibe valores del canal usando el bucle for n := range c. Cuando se recibe un valor, se imprime en la consola.

Esperar a que las goroutines terminen: La llamada time.Sleep(time.Second) asegura que la goroutine principal espere a que las otras goroutines terminen antes de salir.

Hasta ahora:

Creamos 5 goroutines (cocineros) que reciben números por un canal.
Enviamos números al canal para que los cocineros los procesen.
Los cocineros trabajan de forma concurrente, procesando los números a medida que los reciben.

¿Por qué usar concurrencia y paralelismo en Go?

Mejor rendimiento: Especialmente en tareas I/O-bound (como leer archivos o hacer solicitudes HTTP).
Mayor capacidad de respuesta: La aplicación puede seguir respondiendo a otras solicitudes mientras una tarea está bloqueada.
Arquitecturas más escalables: Puedes distribuir el trabajo en múltiples núcleos o máquinas.

¡Recuerda!

La concurrencia y el paralelismo son herramientas poderosas, pero también pueden hacer que el código sea más complejo de entender y depurar. Es importante usarlas con cuidado y comprender sus implicaciones.

¿Quieres profundizar más en algún tema específico?

Podemos explorar conceptos como:

Sincronización: Mutexes, grupos de trabajo, etc.
Patrones de concurrencia: Producer-consumer, pipeline, etc.
Testing concurrente: Cómo probar código concurrente de manera efectiva.

Saludos,
Lucatonny Raudales

X/Twitter
Github

Declaración de liberación Este artículo se reproduce en: https://dev.to/lucatonyraudales/go-concurrencia-vs-paralelismo-para-tontos-2fnn?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarla.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3