No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Range, Close y Select en channels

29/36
Recursos

Aportes 22

Preguntas 13

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

  • 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 鈥済o鈥 y 鈥渟elect鈥.

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 鈥渇mt鈥

//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 <- 鈥淢ensaje 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)
		}
	}

}

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

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

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!

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鈥檚 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.

A聽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

len() y cap()