Reputation: 8113
package main
import (
"fmt"
//"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
say("hello") // current goroutine
}
Why result is:
hello
hello
hello
hello
hello
Why is there no world
?
Answer: (edited:) If I do this, it is good now:
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
runtime.Gosched()
say("hello") // current goroutine
}
Upvotes: 1
Views: 1942
Reputation: 1
It's because the main goroutine exits too early. When the main goroutine exits, the process will exit, so there is no chance for other goroutines to run. If you wish the goroutines to run, keep the main routine alive long enough.
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
runtime.Gosched()
say("hello") // current goroutine
time.Sleep(1 * time.Second) // this line
}
Upvotes: 0
Reputation: 48154
You're just experiencing a timing issue because you're not 'coordinating' your go routines. The common way to handle this is with a wait guard. The other option I see from time to time using channels and a blocking select. A wait guard implementation would look something like this;
func main() {
wg := sync.WaitGroup{}
wg.Add(1)
go say("world") // create a new goroutine
wg.Add(1)
say("hello") // current goroutine
wg.Wait()
}
While the channel option (not actually interesting or useful in this example) is something more like this;
func main() {
done := make(chan bool)
go say("world", done) // create a new goroutine
say("hello", done) // current goroutine
select {
case fin := <- done:
//on finished
return
}
}
func say(s string, chan bool) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
done <- true
}
With the example above though, the first call to say completing would allow the program to finish executing. To ensure both finish you'd have to pass different channels to each and have blocking reads on both. This is more a pattern I would use when your go routines are doing real work and you want to bring data to aggregate data from them or need more complex coordination (like spawning new goroutines based on the results of previous ones ect).
Upvotes: 3
Reputation: 109464
You're not allowing the goroutine to run before main()
exits.
Even though the second call to say
blocks (briefly), there's no guarantee that the first goroutine can run. You need to wait for both to return, which is often done with a WaitGroup
var wg sync.WaitGroup
func say(s string) {
defer wg.Done()
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
wg.Add(1)
go say("world") // create a new goroutine
wg.Add(1)
say("hello") // current goroutine
wg.Wait()
}
Upvotes: 2