Reputation: 23749
Given this playground:
package main
import "fmt"
func main() {
go oneFunc().anotherFunc()
}
func oneFunc() something {
fmt.Println("oneFunc")
return something{}
}
type something struct{}
func (s something) anotherFunc() {
fmt.Println("anotherFunc")
}
Why is the output:
oneFunc
and "anotherFunc" is never printed?
Upvotes: 3
Views: 1062
Reputation: 57639
The expression behind the go
keyword is evaluated and the function value of that expression is then executed concurrently.
So, in your example oneFunc()
is called, hence the oneFunc
output, and the method anotherFunc
on the returned instance is called concurrently.
However, your program terminates before the goroutine can run which
is why you don't see anotherFunc
printed.
Solution: Use sync.WaitGroup
or channels for synchronization.
To actually (empirically) verify that your go
call executes anotherFunc
concurrently
and not oneFunc
you can print the stack in each function and compare the output.
Example (on play):
var wg = sync.WaitGroup{}
func main() {
wg.Add(1)
go oneFunc().anotherFunc()
wg.Wait()
}
func oneFunc() something {
fmt.Println("oneFunc")
buf := make([]byte, 4096)
runtime.Stack(buf, false)
fmt.Println("Stack of oneFunc:", string(buf))
return something{}
}
type something struct{}
func (s something) anotherFunc() {
defer wg.Done()
buf := make([]byte, 4096)
runtime.Stack(buf, false)
fmt.Println("Stack of anotherFunc:", string(buf))
fmt.Println("anotherFunc")
}
You will see something like this:
oneFunc
Stack of oneFunc: goroutine 1 [running]:
main.oneFunc()
/tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:20 +0x118
main.main()
/tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:11 +0x50
Stack of anotherFunc: goroutine 2 [running]:
main.something.anotherFunc()
/tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:32 +0xb2
created by main.main
/tmpfs/gosandbox-342f581d_b6e8aa8b_334a0f88_c8221b7e_20882985/prog.go:11 +0x69
anotherFunc
The stack trace even tells you that the two functions are running in different goroutines, no comparison of method calls needed.
Upvotes: 2
Reputation: 18546
The way that I like to about it is this, go
– like defer
– consumes the last invocation, or pair parentheses, on the line and will invoke that function out of order. Every invocation before that is synchronous.
Where go
makes the invocation concurrent. And defer
delays invocation until current function returns.
There is a really good example of this in the defer
section of Effective Go
Upvotes: 2
Reputation: 7908
anotherFunc
doesn't execute until oneFunc
returns a value. Because of this, the program exits before anotherFunc
is able to run. You need to wait for anotherFunc
to run before main
exits.
You can do this via Go channels. For Example:
http://play.golang.org/p/dWoLB9afSj
package main
import "fmt"
func main() {
ch := make(chan int)
go oneFunc(ch).anotherFunc()
fmt.Println("Waiting...")
<-ch
fmt.Println("Done.")
}
func oneFunc(ch chan int) something {
fmt.Println("oneFunc")
return something{ch}
}
type something struct{
ch chan int
}
func (s something) anotherFunc() {
fmt.Println("anotherFunc")
s.ch <- 1
}
Upvotes: 5