golang - ¿Por qué fmt.Println dentro de un goroutine no imprime una línea?
goroutine timeout (5)
Tengo el siguiente código:
package main
import "net"
import "fmt"
import "bufio"
func main() {
conn, _ := net.Dial("tcp", "irc.freenode.net:6667")
reader := bufio.NewReader(conn)
go func() {
str, err := reader.ReadString(''/n'')
if err != nil {
// handle it
fmt.Println(err)
}
fmt.Println(str)
}()
}
Si no tengo el código que lee desde el buffer en un goroutine, genera un mensaje como este, que es lo que espero que suceda:
:zelazny.freenode.net NOTICE * :*** Looking up your hostname...
Sin embargo, tenerlo dentro de un goroutine no imprime nada.
¿Alguien puede explicar por qué es eso?
Como se mencionó anteriormente, el func principal () saldrá antes de que el goroutine tenga la oportunidad de correr. Los goroutines como hilos livianos se ejecutan en su propio tiempo. Para depurar el truco que suelo usar es agregar un sueño justo después de mi goroutine, el tiempo suficiente para que mi goroutine termine. Aquí hay un ejemplo muy básico:
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Hello gopher!")
go print_nums(10)
time.Sleep(time.Millisecond * 100) // if i take this line out all i will see is hello and bye gopher!
fmt.Println("Bye gopher!")
}
func print_nums(num int) {
i := 0
for i < num {
fmt.Println(i)
i++
}
}
Escribir datos en un canal ch
al final de la rutina y leer los datos de la salida de la rutina puede hacer que la función principal esté esperando el mensaje de impresión de la rutina.
Aquí hay un ejemplo:
package main
import "net"
import "fmt"
import "bufio"
func main() {
conn, _ := net.Dial("tcp", "irc.freenode.net:6667")
reader := bufio.NewReader(conn)
ch := make(chan byte, 1)
go func() {
str, err := reader.ReadString(''/n'')
if err != nil {
// handle it
fmt.Println(err)
}
fmt.Println(str)
ch <- 1
}()
<-ch
}
Necesita agregar un retraso como el time.Sleep(3 * time.Second)
(esto espera 3 segundos).
La rutina se cierra cuando finaliza el programa. Tuve exactamente el mismo problema.
Otra forma común que verás implementado de esperar a que los goroutines finalicen es http://golang.org/pkg/sync/#WaitGroup . puede waitGroup.Add(1)
para cada goroutine iniciado, luego waitGroup.Done()
en el goroutine después de que termine, y main puede waitGroup.Wait()
y bloqueará hasta que se haya llamado a waitGroup.Done()
para cada Add .
Su programa saldrá cuando la función main()
finalice. Es probable que esto suceda antes de que tu goroutine tenga tiempo de ejecutar e imprimir su salida.
Una opción sería tener el bloque principal de goroutine leyendo de un canal, y hacer que la rutina escriba al canal cuando haya completado su trabajo.