run golang close go concurrency goroutine

close - golang run



No hay salida de goroutine en Go (3)

Mientras SayHello() ejecuta como se esperaba, la gorutina no imprime nada.

package main import "fmt" func SayHello() { for i := 0; i < 10 ; i++ { fmt.Print(i, " ") } } func main() { SayHello() go SayHello() }


Alternativamente (a la respuesta de icza) puede usar WaitGroup del paquete de sync y la función anónima para evitar alterar SayHello original.

package main import ( "fmt" "sync" ) func SayHello() { for i := 0; i < 10; i++ { fmt.Print(i, " ") } } func main() { SayHello() var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() SayHello() }() wg.Wait() }

Para imprimir números, ejecute simultáneamente cada declaración de impresión en una rutina separada como la siguiente

package main import ( "fmt" "math/rand" "sync" "time" ) func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(fnScopeI int) { defer wg.Done() // next two strings are here just to show routines work simultaneously amt := time.Duration(rand.Intn(250)) time.Sleep(time.Millisecond * amt) fmt.Print(fnScopeI, " ") }(i) } wg.Wait() }


Como otros han mencionado, el programa Go sale cuando la función main regresa.

Una opción es usar algo como sync.WaitGroup para esperar a las otras gorutinas que main ha generado antes de regresar de main .

Otra opción es llamar a runtime.Goexit() en main . Desde el godoc :

Goexit termina la rutina que lo llama. Ninguna otra gorutina se ve afectada. Goexit ejecuta todas las llamadas diferidas antes de terminar la rutina. Debido a que Goexit no es pánico, cualquier llamada de recuperación en esas funciones diferidas devolverá nulo.

Llamar a Goexit desde la goroutina principal termina esa goroutina sin que la función principal regrese. Dado que func main no ha regresado, el programa continúa la ejecución de otras gorutinas. Si todas las otras gorutinas salen, el programa se bloquea.

Esto permite que la rutina principal deje de ejecutarse mientras las rutinas en segundo plano continúan ejecutándose. Por ejemplo:

package main import ( "fmt" "runtime" "time" ) func f() { for i := 0; ; i++ { fmt.Println(i) time.Sleep(10 * time.Millisecond) } } func main() { go f() runtime.Goexit() }

Esto puede ser más limpio que bloquear para siempre en la función principal, especialmente para programas que son infinitos. Una desventaja es que si todas las rutinas de un proceso regresan o salen (incluida la principal), Go detectará esto como un error y pánico:

fatal error: no goroutines (main called runtime.Goexit) - deadlock!

Para evitar esto, al menos una gorutina debe llamar a os.Exit antes de que regrese. Llamar a os.Exit(0) inmediatamente termina el programa e indica que lo hizo sin error. Por ejemplo:

package main import ( "fmt" "os" "runtime" "time" ) func f() { for i := 0; i < 10; i++ { fmt.Println(i) time.Sleep(10 * time.Millisecond) } os.Exit(0) } func main() { go f() runtime.Goexit() }


Cuando finaliza su función main() , su programa también finaliza. No espera a que otras gorutinas terminen.

Citando desde el Go Idioma Especificación: Ejecución del programa :

La ejecución del programa comienza inicializando el paquete principal y luego invocando la función main . Cuando la invocación de esa función regresa, el programa sale. No espera a que se completen otras gorutinas (no main ).

Vea esta respuesta para más detalles.

Debe decirle a su función main() que espere a que la función SayHello() inicie como una rutina completa. Puede sincronizarlos con canales, por ejemplo:

func SayHello(done chan int) { for i := 0; i < 10; i++ { fmt.Print(i, " ") } if done != nil { done <- 0 // Signal that we''re done } } func main() { SayHello(nil) // Passing nil: we don''t want notification here done := make(chan int) go SayHello(done) <-done // Wait until done signal arrives }

Otra alternativa es señalar la finalización cerrando el canal:

func SayHello(done chan struct{}) { for i := 0; i < 10; i++ { fmt.Print(i, " ") } if done != nil { close(done) // Signal that we''re done } } func main() { SayHello(nil) // Passing nil: we don''t want notification here done := make(chan struct{}) go SayHello(done) <-done // A receive from a closed channel returns the zero value immediately }

Notas:

Según sus ediciones / comentarios: si desea que las 2 funciones de ejecución de SayHello() impriman números "mixtos" al azar: no tiene garantía de observar este comportamiento. Nuevamente, vea la respuesta antes mencionada para más detalles. El modelo Go Memory solo garantiza que ciertos eventos sucedan antes que otros eventos, no tiene garantía de cómo se ejecutan 2 goroutines concurrentes.

Puede experimentar con él, pero sepa que el resultado no será determinista. Primero debes habilitar múltiples goroutines activos para ser ejecutados con:

runtime.GOMAXPROCS(2)

Y segundo, primero debe iniciar SayHello() como una rutina porque su código actual primero ejecuta SayHello() en la rutina principal y solo una vez que termina, comienza el otro:

runtime.GOMAXPROCS(2) done := make(chan struct{}) go SayHello(done) // FIRST START goroutine SayHello(nil) // And then call SayHello() in the main goroutine <-done // Wait for completion