No hay salida de goroutine

Resuelto Dinesh Panchananam asked hace 9 años • 3 respuestas

Si bien SayHello()se ejecuta como se esperaba, la rutina no imprime nada.

package main

import "fmt"

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

func main() {
    SayHello()
    go SayHello()
}
Dinesh Panchananam avatar Mar 10 '15 14:03 Dinesh Panchananam
Aceptado

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

Citando la especificación de Go Language: Ejecución del programa :

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

Consulte esta respuesta para obtener más detalles.

Debe decirle a su main()función que espere a SayHello()que se complete la función iniciada como una rutina. Puedes 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 SayHello()funciones en ejecución impriman números "mixtos" al azar: no tiene garantía de observar tal comportamiento. Nuevamente, consulte la respuesta antes mencionada para obtener más detalles. El modelo Go Memory solo garantiza que ciertos eventos sucedan antes que otros, no tiene garantía de cómo se ejecutan 2 gorutinas simultáneas.

Puedes experimentar con ello, pero debes saber que el resultado no será determinista. Primero debe habilitar la ejecución de múltiples rutinas activas con:

runtime.GOMAXPROCS(2)

Y en segundo lugar, primero debe comenzar SayHello()como una rutina porque su código actual se ejecuta primero SayHello()en la rutina principal y solo una vez que finaliza inicia la otra:

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
icza avatar Mar 10 '2015 07:03 icza

Alternativamente (a la respuesta de icza), puede usar WaitGroupfrom syncpaquete y función anónima para evitar alterar el original SayHello.

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 simultáneamente, ejecute 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()
}
Sundrique avatar Mar 10 '2015 07:03 Sundrique