I'm very new to go and I'm not sure why this code has this output. I understand that sleep will cause the new goroutine to start the other thread for the specified amount of time. I'm trying to sequentially map out the logic and it looks like "world" should always print before "hello".
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(1 * time.Millisecond)
fmt.Println(s, i)
}
}
func main() {
go say("world")
say("hello")
}
Actual Output:
world 0
hello 0
hello 1
world 1
world 2
hello 2
hello 3
world 3
world 4
hello 4
Expected Output:
world 0
hello 0
world 1
hello 1
world 2
hello 2
...etc
I understand that sleep will cause the new goroutine to start the other thread for the specified amount of time
This is partly incorrect!
This would be correct on a machine with only one core where only one thread can be executed at a time.
On a machine with multiple cores go can execute as many goroutines parallel as there are cores. With parallel executed goroutines there is no guarantee at all, what will be executed before or after.
You cannot say with any certainty what order concurrent operations will "always" execute in. That's how concurrency works. If you want to control the order of execution, either don't execute concurrently, or use synchronization constructs (e.g. mutex, channel) to control the order of operations.
As others have said, there are no guarantees you can assume about the order of execution.
The Go scheduler has an internal algorithm that decides how to allocate the processor and there is little you can do to control this without resorting to synchronization (which would be the right approach to take here).
If you are interested in learning how to control synchronization between tasks, take a look at the sync
package, and also at how channels
work:
https://tour.golang.org/concurrency/2
However, I want to add something that others have not mentioned, and while it does not allow you to control execution order, it might be worth commenting due to the nature of the question.
There is a runtime.Gosched
function that you can use to hint the scheduler. It would yield the processor so it is likely that other threads will execute.
https://golang.org/pkg/runtime/#Gosched
If you add a call to Gosched
instead of sleeping, in my tests it is much more likely that "hello" and "world" would output in order (though again, there is no guarantee and they will appear in random order at times).
Try it like this:
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s, i)
runtime.Gosched()
}
}
func main() {
go say("world")
say("hello")
}
Lastly, take a look at this article which you might find interesting as well:
http://container-solutions.com/surprise-golang-thread-scheduling/