It is a bit strange that Hello World did not get printed. So what happened?
goroutines always run in the background. When a goroutine is executed, here, Go does not block the program execution, unlike normal function call as we have seen in the previous example. Instead, the control is returned immediately to the next line of code and any returned value from goroutine is ignored. But even then, why we can’t see the function output?
By default, every Go standalone application creates one goroutine. This is known as the main goroutine that the main function operates on. In the above case, the main goroutine spawns another goroutine of printHellofunction, let’s call it printHello goroutine. Hence when we execute the above program, there are two goroutines running concurrently. As we saw in the earlier program, goroutines are scheduled cooperatively.
Hence when the main goroutine starts executing, go scheduler dot not pass control to the printHello goroutine until the main goroutine does not execute completely. Unfortunately, when the main goroutine is done with execution, the program terminates immediately and scheduler did not get time to schedule printHello goroutine.
But as we know from other lessons, using blocking condition, we can pass control to other goroutines manually AKA telling the scheduler to schedule other available goroutines. Let’s use time.Sleep() call to do it.
We have modified program in such a way that before main goroutine pass control to the last line of code, we pass control to printHello goroutine using time.Sleep(10 * time.Millisecond) call. In this case, the main goroutine sleeps for 10 milli-seconds and won’t be scheduled again for another 10 milliseconds.
Once printHello goroutine executes, it prints ‘Hello World!’ to the console and terminates, then the main goroutine is scheduled again (after 10 milliseconds) to execute the last line of code where stack pointer is. Hence the above program yields the following result.
If we add a sleep call inside the function which will tell goroutine to schedule another available goroutine, in this case, the main goroutine. But from the last lesson, we learned that only non-sleeping goroutines are considered for scheduling, main won’t be scheduled again for 10 milli-seconds while it’s sleeping.
Hence the main goroutine will print ‘main execution started’, spawning printHello goroutine but still actively running, then sleeping for 10 milli-seconds and passing control to printHello goroutine.
printHello goroutine then will sleep for 1 milli-second telling the scheduler to schedule another goroutine but since there isn’t any available, waking up after 1 milli-second and printing ‘Hello World!’ and then dying. Then the main goroutine will wake up after a few milliseconds, printing ‘main execution stopped’ and exiting the program.
The above program starts two Goroutines in line nos. 21 and 22. These two Goroutines now run concurrently.
The numbers Goroutine sleeps initially for 250 milliseconds and then prints 1, then sleeps again and prints 2 and the same cycle happens till it prints 5.
Similarly the alphabets Goroutine prints alphabets from a to e and has 400 milliseconds sleep time. The main Goroutine initiates the numbers and alphabets Goroutines, sleeps for 3000 milliseconds and then terminates.
The first portion of the image in blue color represents the numbers Goroutine, the second portion in maroon color represents the alphabets Goroutine, the third portion in green represents the main Goroutine and the final portion in black merges all the above three and shows us how the program works.
The strings like 0 ms, 250 ms at the top of each box represent the time in milliseconds and the output is represented in the bottom of each box as 1, 2, 3 and so on. The blue box tells us that 1 is printed after 250 ms, 2 is printed after 500 ms and so on.
The bottom of last black box has values 1 a 2 3 b 4 c 5 d e main terminated which is the output of the program as well. The image is self explanatory and you will be able to understand how the program works.