2015-03-10 16 views
6

Podczas gdy SayHello() wykonuje się zgodnie z oczekiwaniami, goroutine nic nie drukuje.Brak wyjścia z goroutine w Go

package main 

import "fmt" 

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

func main() { 
    SayHello() 
    go SayHello() 
} 
+0

możliwym duplikatu [Goroutine nie wykonuje jeśli time.Sleep włączone] (http: // stackoverflow. com/questions/28307783/goroutine-does-not-execute-if-time-sleep-included) –

Odpowiedz

15

Po zakończeniu funkcji main() Twój program również się kończy. Nie czeka na zakończenie innych goroutinów.

Cytując z Go Language Specification: Program Execution:

wykonanie programu rozpoczyna się od inicjalizacji główny pakiet, a następnie wywołując funkcję main. Gdy funkcja ta powróci, program zostanie zamknięty. Nie czeka na zakończenie innych (nie main) gorutyn.

Aby uzyskać więcej informacji, zobacz this answer.

Musisz powiedzieć swojej funkcji main(), aby poczekać na zakończenie funkcji SayHello() jako goroutine. Możesz zsynchronizować je z kanałów na przykład:

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 
} 

Inną alternatywą jest sygnał zakończenia zamykając kanał:

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 
} 

Uwagi:

Według swoje modyfikacje/komentarz: jeśli chcesz, aby 2 działające funkcje SayHello() drukowały losowo "mieszane" numery: nie masz gwarancji, że będziesz obserwować takie zachowanie. Ponownie zobacz aforementioned answer, aby uzyskać więcej informacji. Go Memory Model gwarantuje tylko, że pewne zdarzenia zdarzają się przed innymi zdarzeniami, nie masz gwarancji, jak zostaną wykonane 2 równoczesne goroutiny.

Możesz eksperymentować z tym, ale wiedz, że wynik nie będzie deterministyczny. Najpierw trzeba włączyć wiele aktywnych goroutines być wykonany z:

runtime.GOMAXPROCS(2) 

A po drugie trzeba najpierw uruchomić SayHello() jako goroutine ponieważ aktualna kod najpierw wykonuje SayHello() w głównym goroutine i dopiero po jej zakończeniu rozpoczyna się druga jeden:

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 
+1

Dobrze, po prostu zrozumiałem twoją edycję po przeczytaniu http://dave.cheney.net/2014/03/19/channel- aksjomaty: wysyłanie do bloków kanału 'nil' na zawsze, Odbiór z bloków kanału' nil' na zawsze. – VonC

+0

@icza proszę sprawdzić zmiany. –

+0

@ DineshPanchananam Co masz na myśli, mówiąc o "nieporządnej" modzie? Czy spodziewasz się losowych liczb z dwóch działających funkcji 'SayHello()'? – icza

5

Alternatywnie (aby odpowiedzieć icza'S) można użyć WaitGroup z sync pakietu i funkcji anonimowej, aby uniknąć zmieniania oryginalnego 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() 
} 

W celu wydrukowania numerów jednocześnie uruchomić każdą instrukcję drukowania w oddzielnej procedurze jak na poniższym

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() 
} 
+0

proszę sprawdzić zmiany –

+0

@ DineshPanchananam Czy chcesz wydrukować każdy numer w osobnej procedurze? – Sundrique

+0

Nie. Spodziewałem się czegoś "" równoległego "" ", ale myślę, że się mylę." –

Powiązane problemy