Si se incluye “fmt.Println(<- chanel)” en el mismo ciclo for del “go” no se obtiene el mismo rendimiento.
for _, server := range servers {
go checkServer(server, chanel)
fmt.Println(<- chanel)
}
Introducción a Go
Mi primer programa en Go
Instalación en Mac y Windows
Instalar VS Code
Comandos básicos de Go
Analizando un programa en Go
Nuestra Primera Aplicación Go
Descripción del proyecto 1: Calculadora
Leer inputs desde la consola
Manejo de errores y uso de If
Switch
Lista de Tareas
Structs y Receivers
Descripción del proyecto 2: Lista de Tareas
Structs para Lista de Tareas
Punteros
Punteros en Structs
Uso de Slices
Ciclo For
Implementar For en Struct
Interfaces
¿Qué es una interfaz?
Maps
¿Por qué las Interfaces?
Creando la Interfaz Animal
Imprimiendo el contenido de una Página Web usando Interfaces
Goroutines y Channels
Introducción al problema de la Concurrencia
GoRoutines
Channels
Implementación de Goroutines y channels
Construyendo un Servidor Web
Ciclos While y For
Descripción de Servidor Web
Creando el Servidor
Manejando rutas en backend
¿Qué es un Middleware?
Manejando Request HTTP
Asignando Rutas HTTP
Agregando Middlewares
Agregando Multiples Middlewares
Agregando otro Middleware
Manejando POST
Manejando Modelos y JSON
Respondiendo Request JSON
Go Modules creando nuestro primer módulo en Go
Implementando nuestro primer módulo en Go
Conclusiones del Curso y siguientes pasos
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Aportes 24
Preguntas 4
Si se incluye “fmt.Println(<- chanel)” en el mismo ciclo for del “go” no se obtiene el mismo rendimiento.
for _, server := range servers {
go checkServer(server, chanel)
fmt.Println(<- chanel)
}
Quería aclarar algunas cosas
La primera vez que ejecuta el programa, no aparecen los mensajes, porque primero se acaba de ejecutar el main, que las subrutinas, esto se podría solucionar con un sleep que es muy mala practica, un waitgroup que espera que se ejecuten todas las gorutinas https://gobyexample.com/waitgroups o con canales
Como esta tarea no requiere compartir las respuestas entre las go rutinas waitgroup es una muy buena opción
Quisiera aclarar que la go rutina no va a esperar hasta que acabe la primera para continuar. Trataré de explicarlo
Si tenemos dos gorutinas , que tiene que ejecutar una función
-- Go rutina 1
-- Go rutina 2
func Sumar(num1, num2 int){
imprime un mensaje
hace la suma
la envia por el canal
c <- resultado
}
el proceso sería asi:
Ambas gorutinas empiezan, imprimen, suman, pero al momento de enviar por el canal la primera envia porque nadie ha usado el canal, pero la segunda se queda en pausa, esperando que la primera envie la información, cuando ya el mensaje haya sido recibido por alguien, ahi si la segunda envie su mensaje
for elem := range queue {
fmt.Println(elem)
}
La palabra clave go
lo que hace es crear un nuevo proceso o hilo que se ejecuta independiente de main
.
Main al mandar a ejecutar goroutines, aunque no hayan acabado, termina la ejecución de su código. Channels
es el mecanismo de comunicación entre las mismas goroutines y también el proceso main.
// definición de un channel.
c := make(chan string)
// sintaxis para transmitir información al channel
c <- "sending data"
// sintaxis para recibir información del channel
received := <-c
Los channels alojan un tipo específico de dato que se debe definir explícitamente.
Si únicamente pusiéramos una vez la recepción de información de un channel, main
continuaría con su ejecución, porque no especificamos que tenía que esperar más información. Para recibir la información de múltiples goroutines, tenemos que definir las veces que nuestro channel debe esperar información.
Por otro lado, si no recibiera información se quedaría bloqueado, porque utilizamos un channel de tipo unbuffered
, un tipo de channel que no definimos su capacidad o tamaño de manera explícita, que se quedaría esperando a recibir un información.
Me pueden ayudar para saber porque me sale el error to many arguments in call to checkStatusServer
have (string, chan string)
want (string)
El codigo con el ejercicio funcionó de maravilla pero me quedó la duda de porque a mí si me salió está advertencia y al tutor no.
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
startWatch := time.Now()
channel1 := make(chan string)
servers := []string{
"http://platzi.com",
"http://google.com",
"http://facebook.com",
"http://instagram.com",
}
for _, server := range servers {
go checkStatusServer(server, channel1)
}
for index, _ := range servers {
fmt.Println(<-channel1, index+1)
}
timeExec := time.Since(startWatch)
fmt.Printf("Execution time: %s", timeExec)
}
func checkStatusServer(server string, channel chan string) {
_, err := http.Get(server)
if err != nil {
//fmt.Println(server, "Is not Available =(")
channel <- server + " Is not Available =("
} else {
//fmt.Println(server, "It's working OK")
channel <- server + " It's working OK"
}
}
No se si estoy mal, pero sin las rutinas el proceso tomo 2.086 segundos, y usando rutinas tomo 2.736 segundos, entonces no veo la mejora al usar las Goroutines o no se implementarion bien, porque aunque los servidores no siempre responden en un tiempo fijo la idea idea era mejorar los tiempos y 0.7seg es bastante para los llamados
Les comparto el mismo codigo pero con waiting groups 😉
package main
import (
"fmt"
"net/http"
"sync"
"time"
)
func main() {
start := time.Now()
servers := []string{
"https://www.festivalestereopicnic.com/",
"https://www.eltiempo.com/",
"https://platzi.com/",
}
var wg sync.WaitGroup
for _, server := range servers {
wg.Add(1)
go checkServer(server, &wg)
}
wg.Wait()
finalTime := time.Since(start)
fmt.Println("Execution time", finalTime)
}
func checkServer(server string, wg *sync.WaitGroup) {
_, err := http.Get(server)
if err != nil {
fmt.Println(server, "Not available")
} else {
fmt.Println(server, "Is UP :) ")
}
wg.Done()
}
Se nota la diferencia 😃
Les dejo mi código, chequea cada link cada 5 segundos.
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
URLS := []string{
"platzi",
"google",
"facebook",
"instagram",
}
c := make(chan string, len(URLS))
for _, u := range URLS {
c <- u
}
for u := range c {
go reviewServer(u, c)
}
}
func reviewServer(u string, c chan<- string) {
_, err := http.Get(u)
if err != nil {
fmt.Println(u, "is down.")
} else {
fmt.Println(u, "is up.")
}
time.Sleep(5 * time.Second)
c <- u
}
¿Es posible iterar sobre el canal con un for range?
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
inicio := time.Now()
ch := make(chan string)
servidores := []string{
"h t t p : / / p l a tz i . c o m",
"h t t p : // g o o g le . c o m ",
"h t t p : / / f ac e b o o k . c o m ",
"h t t p : / / I n s t a g ra m . co m",
}
for _, servidor := range servidores {
go revisarServidor(servidor, ch)
}
for i := 0; i < len(servidores); i++ {
fmt.Println(<-ch)
}
tiempoPasado := time.Since(inicio)
fmt.Printf("Done in %s", tiempoPasado)
}
func revisarServidor(servidor string, ch chan string) {
_, err := http.Get(servidor)
if err != nil {
ch <- servidor + "no esta disponible"
} else {
ch <- servidor + "esta funcionando"
}
}
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
channel := make(chan string, 4)
links := []string{
"https://www.digitalocean.com",
"https://jsonplaceholder.typicode.com",
"https://platzi.com/",
"https://github.com/",
}
start := time.Now()
go func() {
for _, url := range links {
if _, err := http.Get(url); err != nil {
fmt.Println("El servidor esta fuera!")
} else {
channel <- fmt.Sprintf("%s --> Ok", url)
}
}
defer close(channel)
}()
for msg := range channel {
fmt.Println(msg)
}
end := time.Since(start)
fmt.Println(end)
}
la combinación Goroutines y channels hacen de Go un lenguaje muy poderoso.
Que poder tan abismal tiene Go routines y que sencillo fue implementarlo.
según entiendo Go administra los hilos para no tener que abrir tantos hilos como en otros lenguajes.
Esta es una ventaja total de go contra el resto.
Los channel nos dice que paso con la ejecucion de las gorutines
con la palabra reservada **chan string ** no dice que estamos declarando un canal con su tipo de datos
canal es el channel y con la flecha <- lo que esta a la derecha de la flecha sera el contenido de lo que se esta transmitiendo
Con gorutines utilizamos programacion concurrente, para que se secuencial.
De esta manera imprimira solo el nombre del servidor por ejemplo, “platzi”, y no toda la URL “http://platzi.com”
<code>servers := []string{
"platzi",
"youtube",
"google",
"instagram",
"facebook",
"twitter",
}
for _, server := range servers {
go checkStatus("http://"+server+".com", channel)
}
for i := 0; i < len(servers); i++ {
avaible := <-channel
fmt.Println(avaible)
}
finishProcessTime := time.Since(startProcessTime)
fmt.Printf("estimated time to get result: ")
fmt.Println(finishProcessTime)
}
func checkStatus(server string, channel chan string) {
_, err := http.Get(server)
svWithExtension := strings.Split(server, "//")
svName := strings.Split(svWithExtension[1], ".")
sv := svName[0]
if err != nil {
channel <- sv + " status: NO AVAIBLE"
}
channel <- sv + " status: AVAIBLE"
Obtienes el mismo resultado al escribir el Println dentro del for con la concurrencia:
//recorrer slice
for _, servidor := range servidores{
go revisarServidor(servidor, canal)
//leer un canal
fmt.Println(<-canal)
}```
con esto reduces las lineas de codigo
Me pasó que las rutinas morian antes de terminar de ejecutarse .-. pensé que habia hecho algo mal xd
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
canal := make(chan string)
servidores := []string{
"https://platzi.com" ,
"https://google.com",
"https://facebokkkkok.com" ,
"https://Instagram.com",
}
fmt.Print("Iniciando revisión de servidores sin aplicar concurrencia...\n\n")
inicio := time.Now()
for _, servidor := range servidores {
revisarServidorSinConcurrencia(servidor)
}
tiempoPasado := time.Since(inicio)
fmt.Printf("\n--------------> Done in %s <--------------\n\n", tiempoPasado)
fmt.Print("Iniciando revisión de servidores aplicando concurrencia...\n\n")
inicio2 := time.Now()
for _, servidor := range servidores {
go revisarServidorConConcurrencia(servidor, canal)
}
for i := 0; i < len(servidores); i++ {
fmt.Println(<-canal)
}
tiempoPasado2 := time.Since(inicio2)
fmt.Printf("\n--------------> Done in %s <--------------\n\n", tiempoPasado2)
}
func revisarServidorConConcurrencia(servidor string, canal chan string) {
_, err := http.Get(servidor)
if err != nil {
canal <- servidor + " no esta disponible"
} else {
canal <- servidor + " funciona correctamente"
}
}
func revisarServidorSinConcurrencia(servidor string) {
_, err := http.Get(servidor)
if err != nil {
fmt.Println(servidor, "no esta disponible")
} else {
fmt.Println(servidor, "funciona correctamente")
}
}
quería resaltar que el asincronismo y la concurrencia no son lo mismo.
soy el unico que nota que los canales aumentan levemente el tiempo de ejecucion ?
Para crear un canal con varios valores como un objeto puedes crear un struct
//MessageStruct Struct for message
type MessageStruct struct {
message string
status bool
err error
}
c := make(chan MessageStruct)
Esto creara un canal como un objeto con un message, status y err.
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?
o inicia sesión.