No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Buffered channels como semáforos

24/30
Recursos

Aportes 15

Preguntas 5

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Me encantó como se explicó cerca del minuto 7:00 lo de los cupos de los canales. ¡Gracias por esmerarte tanto Néstor!

Muy buena explicacion por parte del profe, me quedo muy claro 😃

Code with comments:

package main

import (
	"fmt"
	"sync"
	"time"
)

/*
traffic light.

this uses channels and waint groups to 1. execute only 2 doSmth() func
at a time and 2. be able to wait for all of them.

in order of execution it'll:
c := [][] -- two free spaces
c := [routine][] -- one free space
c := [rountine][routine] -- all occupied
c := [][routine] -- one free space
*/

func doSmth(i int, wg *sync.WaitGroup, c chan int) {
	defer wg.Done()
	fmt.Printf("Id: %d -> started...\n", i)
	time.Sleep(time.Second * 4)
	fmt.Printf("Id: %d -> finished...\n", i)

	<- c // frees the space for new routines
}

func main() {
	c := make(chan int, 2) // creates a buffered channel with a capacity of two
	var wg sync.WaitGroup // creates wait group

	for i := 0; i < 10; i++ {
		c <- 1 // alocate a new "instance" in the free space
		wg.Add(1) // adds to the wait group
		go doSmth(i, &wg, c)
	}

	wg.Wait()
}

Esto es brutal. Yo desarrollé un integrador que lee datos de Softland ERP y los inserta en Dynamics CRM. Utilicé C#. Resulta que el API de microsoft permite solo 39 llamadas (Creo que eran como 39) después de ahí me daba un error de muchas peticiones el famoso 429. Yo quería que todo fuera rápido. Desarrollé la llamada de cada entidad con task y me las arreglé para hacerlo en pararelo. Pero se fueron toddas las lineas de una sola vez, si habían 100 lineas las 100 intentaban integrarse a la vez, por supuesto, esto provocó que el sistema me obligara a esperar hasta 5 horas, por lo que en lugar de ganar tiempo obtuve un resultado opuesto. Para evitar este problema dividí el total de ejecuciones en paquetes de 20 llamadas, si hay 100 lineas por integrar, tomo 20, las integro y paso a las siguientes 20. Realizar esta segmentación me costó mucho. Tuve que crear un metodo que ahora manejara los task (forma de trabajar concurrencia en c#) y un contador. Con los channels simplemente creo un objeto y lo paso por parámetro. Impresionante. Quiero migrar en go el integrador, es un refactor dificil, no es conveniente. Es un deseo de un junior lo sé, pero como lo deseo!!

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var wg sync.WaitGroup
	c := make(chan int, 5)

	for i := 0; i < 10; i++ {
		wg.Add(1)
		c <- 1
		go doSomething(i, &wg, c)
	}

	fmt.Println("Waiting for goroutines to finish")

	wg.Wait()

}

func doSomething(i int, wg *sync.WaitGroup, c chan int) {
	defer wg.Done()

	fmt.Printf("id: %d started \n", i)
	time.Sleep(4 * time.Second)
	fmt.Printf("id: %d finished \n", i)

	<-c
}

Gracias Nestor por la explicación literalmente me abriste la mente.

Que clase tan útil!

Se me hace que este concepto será súper útil al implementar una virtual estate machine (para smart contracts por ejemplo)

Néstor, sos un ckack.

He logrado comprender muchísimas cosas, lo mejor de todo es que con lo visto hasta aquí podré realizar muchas optimizaciones e código muy importante de la empresa.

El concepto de buffered channels como semaforos me parece de bastante utilidad para poder delimitar el consumo de recursos relacionados a las gorutinas que se ejecuten. Excelente explicación! 😄

Excelente explicacion! ahora queda mucho mejor el concepto y uso de canales y waitgroup 😄

La utilidad de los channels como semaforos esta francamente bien y tiene multiples usos. Cada dia me gusta más go

Excelente… Buena clasa, todo muy claro

Justo buscaba algo así para la obtención de datos desde un endpoint que tiene aprox 450 paginas y que se consulta cada 3~4 minutos

Excelente explicacion.