No results from goroutine in Go

While SayHello() is executing as expected, goroutine does not print anything.

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

When your main() function terminates, your program ends. This does not wait for the completion of other larynxes.

Quote from Go Language Specification: Running a program :

Program execution begins with initializing the main package and then calling the main function. When this function returns, the program exits. It does not wait for the completion of other (not main ) goroutines.

See this answer for more details.

You must tell your main() function that the SayHello() function will start as goroutine to complete. You can synchronize them with channels, for example:

 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 } 

Another alternative is the completion alarm, closing the channel:

 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 } 

Notes:

According to your changes / comments: if you want the 2 executed SayHello() functions to print “mixed” numbers randomly: you have no guarantee to observe this behavior. Again, see the above answer for more details. The Go memory model ensures that certain events happen before other events, you have no guarantee how 2 parallel goroutines are executed.

You can experiment with it, but you know that the result will not be deterministic. First you must enable the execution of several active goroutines with:

 runtime.GOMAXPROCS(2) 

And secondly, you must first run SayHello() as a goroutine, because your current code first executes SayHello() in the main goroutine, and only after it finishes, run another:

 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 
+31
source

Alternatively (for icza's answer) you can use the WaitGroup package from sync and an anonymous function to avoid changing the 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() } 

To print numbers at the same time, run each print statement in a separate procedure, as shown below.

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

As already mentioned, the Go program terminates when the main function returns.

One option is to use something like sync.WaitGroup to wait for other programs that main spawned before returning from main .

Another option is to call runtime.Goexit() on main . From Godok :

Goexit terminates the program that calls it. No other goroutines are affected. Goexit starts all pending calls until the program terminates. Since Goexit is not a panic, any recovery calls in these deferred functions will return zero.

Calling Goexit from the main program terminates this procedure without returning the func main function. Since the func main function did not return, the program continues to execute other programs. If all other programs terminate, the program crashes.

This allows the main routine to stop executing while background routines continue to run. For instance:

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

This can be cleaner than blocking forever in the main function, especially for endless programs. The downside is that if all the procedures in the process return or exit (including the main program), Go will detect this as an error and panic:

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

To avoid this, at least one program must call os.Exit before it returns. A call to os.Exit(0) immediately terminates the program and indicates that it did so without error. For instance:

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

Source: https://habr.com/ru/post/983573/


All Articles