It’s unpredictable actually. What you see on-screen is the output of all 3 goroutines chaotically smashed together.
If you’re sharp, you should notice there is a missing data flow “management” problem at the on-screen output.
The current case is like having a team running a 100 yard race. Everyone starts at the same time but it’s hard to predict who runs at 8.3 mph at 4th second (t=4s) and which lane ended 1st for every matches.
main, you delegated 2 processes to do
printAlpha respectively onto the same output. Once all 3 goroutines (
main, “lower” goroutine, and “upper” goroutine) started, it’s hard to say which runs first, implementing at the moment etc, although the start time is clear that
main is the first, “lower” is second, and “upper” is third. Also, keep in mind that starting a new goroutine does not guarantee that new goroutine will be scheduled immediately.
Here’s a screenshot that I ran your function with benchmark tools in my local machine. Notice each lines are not consistent. The highlighted one is the lowercase runs first.
As for goroutine technicalities. Dave wrote a very good technical article in his blog here: https://dave.cheney.net/2015/08/08/performance-without-the-event-loop.
What to do?
Plan your concurrency clearly like who is suppose to write what to output (who) at when. Then, you can ensure each goroutines works together in a synchronized manner.
Back to the 100 yard race - set up a toll booth right at the finish line then permit who and who should enter first. Then, you can guarantee the output for each lanes.