This post is dedicated to the awesome concept of “Goroutines” in Go. A “Goroutine” (Go Routine?) is a lightweight thread implementation that executes asynchronously with the main process. To define a goroutine, we use the “go” keyword before a function call. Instead of a regular blocking call, the function is then executed asynchronously.
Let’s jump into a quick demonstration. We shall write a program that creates multiple threads, each thread sleeping for a random period of time. For us, the mere mortals, we shall politely ask the threads to print some information so that we can tell when they go to sleep and when they wake up!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package main import ( "fmt" "math/rand" "time" ) func main() { // let's create 5 goroutines using for loop for i := 0; i < 5; i++ { // the go keyword makes it a goroutine, making the function // execute asynchronously instead of a blocking call // we are using anonymous function for simple // demonstration go func(num int) { // let's seed the random number generator rand.Seed(time.Now().UnixNano()) // create a random number for sleeping sleepDuration := rand.Intn(20) // let's print a message before sleeping fmt.Printf("[%d]: Sleeping for %d milisecs \n", num, sleepDuration) // ZzzzZzzZZZzzzz!! time.Sleep(time.Duration(sleepDuration) * time.Millisecond) // Good morning, World! fmt.Printf("[%d]: Woke up! \n", num) }(i) } // delay the main process so that others can print to the terminal var input string fmt.Scanln(&input) } |
The blocking call (from the main process) always executes first. The Scanln() call waits for user input thus allowing the async functions to print their information on the terminal. If we don’t wait, the main process will finish execution and the program will quit. Since the other functions are async, we shall never see their outputs. So we wait and wait for their messages! 🙂
Sample output?
1 2 3 4 5 6 7 8 9 10 11 12 |
Lighthouse: ~/Codes/go $ go run main.go [0]: Sleeping for 3 milisecs [1]: Sleeping for 18 milisecs [2]: Sleeping for 2 milisecs [3]: Sleeping for 16 milisecs [4]: Sleeping for 9 milisecs [2]: Woke up! [0]: Woke up! [4]: Woke up! [3]: Woke up! [1]: Woke up! |
It’s simple, right? In some languages, you have to subclass a built in class and then define specific methods to direct the behavior/actions. In Go, you just define a function and prepend “go” before making the function call. Good thing, you can use anonymous functions and invoke them immediately as well.
For communication between these goroutines, we can use “Channels”. Hope to write another blog post on using channels soon.