No tienes acceso a esta clase

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

Convierte tus certificados en títulos universitarios en USA

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

19 Días
9 Hrs
43 Min
54 Seg

Range, Close y Select en channels

29/36
Recursos

Aportes 26

Preguntas 14

Ordenar por:

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

  • Estoy trabajando en un proyecto donde se reciben datos del estado de una máquina vending(cantidad de productos, temperatura, etc), se debe guardar y analizar los datos para detectar posibles fallas. Go sería muy útil en el procesamiento de muchas máquinas.
package main

import "fmt"

func message(text string, c chan string) {
	c <- text
}

func main() {
	c := make(chan string, 2)

	c <- "Mensaje 1"
	c <- "Mensaje 2"

	fmt.Println(len(c), cap(c))

	// Range y close
	close(c)
	//c<-"Mensaje 3"

	for message := range c {
		fmt.Println(message)
	}

	// Select
	email1 := make(chan string)
	email2 := make(chan string)

	go message("mensaje 1", email1)
	go message("mensaje 2", email2)

	for i := 0; i < 2; i++ {
		select {
		case m1 := <-email1:
			fmt.Println("Email recibido de email 1", m1)
		case m2 := <-email2:
			fmt.Println("Email recibido de email 2", m2)
		}
	}
}

Hola, vengo a compartir como yo hice el close de mi channel; basicamente comparo si el tamaño de mi channel es mayor o igual la capacidad de este, de ser así se cierra. Lo comparto por que creo que así sería en un proyecto de la vida real, pero no se, si tu ya has trabajado con channels en tu trabajo, de ser así por favor comentame si estoy siendo acertado con mi código o no.

if len(c) >= cap(c) {
	close(c)
	fmt.Println("channel closed")
}

A continuación dejo un ejemplo extraído de https://tour.golang.org/concurrency/5 al cual le he añadido comentarios explicando lo que sucede. Este ejemplo me ha ayudado a entender mejor como funciona el “go” y “select”.

package main

import "fmt"

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

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

	// go func()... se lanza de manera concurrente:
	// la línea fmt.Println(<-c) queda en espera hasta que haya algo que leer de <-c.
	// Al ser lanzado concurrentemente, mientras dicha línea espera, se va a la ejecución de fibonacci(c, quit),
	// que guardará valores en c <- x tantas veces se produzca la espera de la línea fmt.Println(<-c).
	// Una vez sale del bucle, pasa a esperar case <-quit, que será satisfecho con quit <- 0, por lo que imprimirá "quit" y finalizará
	// el programa.
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()
	fibonacci(c, quit)
}

Les comparto este ejercicio de concurrencia tomado del Tour de Go. Consiste en comparar dos árboles para saber si contienen los mismos elementos. En este ejercicio, hago los recorridos en forma concurrente utilizando channels.

La idea es recibir los nodos de los arboles en canales y luego ordenar los nodos para compararlos uno a uno.

package main

import (
	"container/list"
	"fmt"
	"golang.org/x/tour/tree"
	"sort"
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	fmt.Println("Walking", t)
	queue := list.New()
	queue.PushBack(t)
	for queue.Len() > 0 {
		current := queue.Back()
		queue.Remove(current)
		var currentTree = current.Value.(*tree.Tree)

		ch <- currentTree.Value

		if currentTree.Left != nil {
			queue.PushBack(currentTree.Left)
		}

		if currentTree.Right != nil {
			queue.PushBack(currentTree.Right)
		}
	}
	fmt.Println("Finished Walking", t)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
	chan1 := make(chan int, 10)
	chan2 := make(chan int, 10)
	defer close(chan1)
	defer close(chan2)

	go Walk(t1, chan1)
	go Walk(t2, chan2)

	arr1 := make([]int, 10)
	arr2 := make([]int, 10)

	for i := 0; i < 10; i++ {
		arr1[i] = <-chan1
	}

	for i := 0; i < 10; i++ {
		arr2[i] = <-chan2
	}

	sort.Ints(arr1)
	sort.Ints(arr2)

	for i := 0; i < 10; i++ {
		if arr1[i] != arr2[i] {
			return false
		}
	}

	return true
}

func main() {
	tree10 := tree.New(1)
	anotherTree10 := tree.New(1)
	tree20 := tree.New(2)

	fmt.Println(tree10, " == ", anotherTree10, " true ==", Same(tree10, anotherTree10))
	fmt.Println(tree10, " == ", tree20, "false ==", Same(tree10, tree20))
}

El codigo del programa con algunos apuntes:

package main

import “fmt”

//del ejemplo message SELECT
func message(text string, c chan string) {
c <- text
}

func main() {
//Maneja 2 datos a la vez
c := make(chan string, 2)
// Inserta 2 mensajes
c <- "Mensaje 1"
c <- “Mensaje 2”
// len: cuantos gorutines hay en un channel
// cap: cantidad maxima que puede almacenar ese channel
fmt.Println(len©, cap©)

// Range y close keywork
//CLOSE: le dice al runtime de GO que va a cerrar el canal una vez dejas de usarlo y no recibe ningun otro dato adicional
close(c)

//c<-"Mensaje 3"
//RANGE: Recorrer la lista, reccoriendo todos los mensajes que estan en ese chanel c
for message := range c {
	fmt.Println(message)
}

// Select: multiples canales sin saber  cual va primero
email1 := make(chan string)
email2 := make(chan string)

go message("mensaje 1", email1)
go message("mensaje 2", email2)
// tener presente la cantidad de channels a manejar para el ciclo, en este ejemplo 2
for i := 0; i < 2; i++ {
	select {
	case m1 := <-email1:
		fmt.Println("Email recibido de email 1", m1)
	case m2 := <-email2:
		fmt.Println("Email recibido de email 2", m2)
	}
}

}

En un proyecto de mantos acuiferos distribuidos en una red multi conectada, no me interesa tener los datos secuenciales del flujo de presion y gasto que hay, si se puede, cada segundo.
Me gustaria poder usar coroutines para poder tener una medicion precisa y exacta de este dato, sin la necesidad de esperar a que la medicion en alguna otra locacion termine o concluya su ciclo.

En mi trabajo insertamos varias bases de datos y y tenemos que esperar a que se incerte una para seguir con la otra me parece que esto podria ayudar

Reto

No sé si sea verdad, pero se me hace que se utilizan en la compra de artículos en línea. Por ejemplo compras en cierto tienda en linea multinacional🛫🚚, y los artículos se encuentran en distintas partes del planeta🌎 y necesita coordinar🤓 cada uno de los paquetes de diferentes clientes, eso si es una locura🤯😵, bueno puede aplicarse. ¿Ustedes que opinan?

Creé algo rudimentario de Observador - Observable:

package main

import (
	"fmt"
	"time"
)

func emisorA(output chan<- string) {
	for {
		output <- "Emisor: A"
		time.Sleep(time.Second * 1)
	}
}

func emisorB(output chan<- string) {
	for {
		output <- "Emisor: b"
		time.Sleep(time.Second * 3)
	}
}

func main() {
	canalA := make(chan string)
	canalB := make(chan string)

	go emisorA(canalA)
	go emisorB(canalB)

	for {
		select {
		case cA := <-canalA:
			fmt.Println(cA)
		case cB := <-canalB:
			fmt.Println(cB)
		}
	}

}

En el minuto 4 lo que pasa es que el script queda en estado de deadlock porque hay un mensaje en espera y no hay ningún consumidor de mensajes. No da error por canal lleno.

fatal error: all goroutines are asleep - deadlock!

Al principio no entendía como funcionaba el channel y select, investigando un poco mas me doy cuenta de por que son necesarios para la concurrencia

conversación con chat gpt: Dame 3 ejemplos del mundo real donde podemos sacar provecho de la concurrencia de GolangChatGPTChatGPT Claro, aquí tienes tres ejemplos del mundo real donde se puede sacar provecho de la concurrencia en Go (Golang): 1. **Servicios web de alta concurrencia**: Muchas aplicaciones web, como plataformas de comercio electrónico o redes sociales, experimentan picos de tráfico repentinos. Go es excelente para manejar estas situaciones debido a su capacidad para manejar múltiples solicitudes concurrentes de manera eficiente. Con la concurrencia en Go, puedes diseñar servidores web que puedan manejar miles de solicitudes simultáneas sin degradación del rendimiento. 2. **Procesamiento de datos en tiempo real**: En aplicaciones que requieren procesamiento de datos en tiempo real, como sistemas de monitoreo de redes o análisis de datos de sensores, la concurrencia de Go es invaluable. Puedes diseñar rutinas concurrentes para procesar datos entrantes mientras mantienes la capacidad de respuesta del sistema. Go proporciona primitivas de concurrencia como goroutines y canales que facilitan la construcción de sistemas de procesamiento de datos eficientes. 3. **Herramientas de desarrollo de software**: En el desarrollo de software, especialmente en herramientas como compiladores, linters (analizadores estáticos de código), y sistemas de gestión de paquetes, la concurrencia en Go puede acelerar significativamente los procesos. Por ejemplo, un compilador escrito en Go puede aprovechar la concurrencia para paralelizar la generación de código, lo que resulta en tiempos de compilación más rápidos. De manera similar, los linters pueden realizar análisis estáticos de código en paralelo para mejorar la eficiencia.

Gracias por la explicación, al fin entendí el uso de Select

```python // Este ejemplo usa select sin el select primero ejecutaria la tarea importante que dura 4 segundos y l aesperaría aun cuando importante y normal ya estén listas package main import ( "fmt" "time" ) func urgentTask(c chan string) { time.Sleep(4 * time.Second) c <- "Urgent Task" } func importantTask(c chan string) { time.Sleep(2 * time.Second) c <- "Important Task" } func normalTask(c chan string) { time.Sleep(1 * time.Second) c <- "Normal Task" } func main() { urgentChan := make(chan string) importantChan := make(chan string) normalChan := make(chan string) go urgentTask(urgentChan) go importantTask(importantChan) go normalTask(normalChan) for i := 0; i < 3; i++ { select { case task := <-urgentChan: fmt.Println("Executing:", task) case task := <-importantChan: fmt.Println("Executing:", task) case task := <-normalChan: fmt.Println("Executing:", task) } } } ```package main import ( "fmt" "time") func urgentTask(c chan string) { time.Sleep(4 \* time.Second) c <- "Urgent Task"} func importantTask(c chan string) { time.Sleep(2 \* time.Second) c <- "Important Task"} func normalTask(c chan string) { time.Sleep(1 \* time.Second) c <- "Normal Task"} func main() { urgentChan := make(chan string) importantChan := make(chan string) normalChan := make(chan string) go urgentTask(urgentChan) go importantTask(importantChan) go normalTask(normalChan) for i := 0; i < 3; i++ { select { case task := <-urgentChan: fmt.Println("Executing:", task) case task := <-importantChan: fmt.Println("Executing:", task) case task := <-normalChan: fmt.Println("Executing:", task) } }}

Reto : Hice un channel llamado c que recibe tipos de dato paciente que es un struct, lo hice usando stringers y channels

package main

import "fmt"

type paciente struct {
	id                          int8
	nombre, condicion, urgencia string
}

func newPatient(text paciente, c chan paciente) {
	c <- text
}
func (p paciente) String() string {
	return fmt.Sprintf("Paciente: %d\n - Nombre: %s\n - Condicion: %s\n - Urgencia: %s\n", p.id, p.nombre, p.condicion, p.urgencia)
}
func main() {

	c := make(chan paciente, 3)
	var paciente0 paciente
	paciente0.id = 0
	paciente0.condicion = "Diabetes"
	paciente0.nombre = "Garcia Fernandez"
	paciente0.urgencia = "Leve"
	var paciente1 paciente
	paciente1.id = 1
	paciente1.condicion = "Infarto"
	paciente1.nombre = "Fabricio Gutierrez"
	paciente1.urgencia = "Severo"
	var paciente2 paciente
	paciente2.id = 2
	paciente2.condicion = "Cancer"
	paciente2.nombre = "Gutierrez Jazmit"
	paciente2.urgencia = "Severo"

	go newPatient(paciente0, c)
	go newPatient(paciente1, c)
	go newPatient(paciente2, c)

	for i := 0; i < cap(c); i++ {
		p := <-c
		fmt.Println(p)

	}
}

Propuesta de reto: python es muy lento y yo estoy entendiendo la concurrecia como un scheduler que determina si darle tiempo a la ejecucion de una tarea o no. presento el problema de adqusicion de datos del cerebro ejemplo.

al hacer el sensado de los canales obtenidos del cerebro tenemos muchas señales que no necesariamente son de mi interes por eso he de primero hacer un proceso de filtrado para cada canal.
eso se me ocurre usar la concurrencia para el fin del preprocesado de datos sin tener que esperar a que un lote de tamaño menor a los demas sea ejecutado para poder continuar con los demas

Ok les deji un aporte con unos comentarios que podría facilitar la comprensión del manejo del select y como funciona el flujo de channels

package main

import "fmt"

func message(text string, c chan<- string) {
	c <- text
}

func main() {
	c := make(chan string, 3)

	c <- "Message1"
	c <- "Message2"

	fmt.Println(len(c), cap(c))

	close(c) //Function to close channel
	// c <- "Message2" This wont be added because the channel is already closed

	for message := range c {
		fmt.Println(message)
	}

	email1 := make(chan string)
	email2 := make(chan string)
	go message("message1", email1)
	go message("message2", email2)
	go message("message3", email1)

	for i := 0; i < 3; i++ { //If you perform a for you have to take into account how many message are you waiting
		select { //With select you can migth know which channel is ready
		case m1 := <-email1:
			fmt.Println("Email recibido de email1", m1)
		case m2 := <-email2:
			fmt.Println("Email recibido de email2", m2)
		}
	}
}

Hola compañeros para este curso les dejo mis apuntes todos escritos en go (Son piezas de codigo de cada clase) en este repositorio por si desean volver a estudiarlas.

Por último he hecho este proyecto llamado Gopher’s Supermarket donde quise poner a prueba todos los conocimientos aprendidos en el curso, espero también puedan darle una mirada y hacerme un pull request si lo consideran necesario.

package main

import "fmt"

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("Quitting...")
			return
		}
	}
}

func main() {
	c := make(chan int, 10)
	quit := make(chan int, 10)

	fmt.Println(len(c))
	fmt.Println(cap(c))
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()
	fibonacci(c, quit)
	close(c)
	close(quit)
}

Select

The select statement lets a goroutine wait on multiple communication operations.

select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.

Un aporte para terminar de entender la concurrencia en go

golang

😎

Una clase muy interesante

Buena recomendacion sobre cerrar el channel

En mi compañía decidimos usar Go para el manejo de grandes lagos de datos entre SAP y el nuevo portal que vamos manejar, creemos que el manejo de datos trayendo, procesándolos y almacenando en SQL y NoSQL será muy eficiente y escaladle.

len() y cap()