Skip to main content
Go Language Fundamentals for Beginners to Advanced
CHAPTER 19 Beginner

Goroutines and Concurrency

Updated: May 17, 2026
5 min read

# CHAPTER 19

Goroutines and Concurrency

1. Introduction

Modern CPUs have 8, 16, or even 64 cores. Traditional code executes sequentially—one line after another on a single core—wasting 90% of your computer's power. Concurrency is the ability to do multiple things at the same time.

In languages like Java or C++, you create OS Threads to achieve this, which are heavy, memory-intensive, and hard to manage. Go was built from the ground up to solve this. Go uses Goroutines—incredibly lightweight, virtual threads that make writing concurrent code effortless.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand Concurrency vs. Parallelism.
  • Spawn a Goroutine using the go keyword.
  • Understand how the Go Scheduler manages execution.
  • Recognize the problem of the main function exiting too early.
  • Use time.Sleep as a basic synchronization method.

3. Concurrency vs Parallelism

  • Concurrency: Dealing with many things at once (e.g., A chef chopping onions, then stirring soup, then going back to onions).
  • Parallelism: Doing many things at exactly the same time (e.g., Two chefs: one chops onions, the other stirs soup).

Go excels at Concurrency. By breaking tasks into Goroutines, the Go runtime automatically distributes them across all available CPU cores, naturally achieving Parallelism!

4. What is a Goroutine?

A Goroutine is a function executing concurrently with other goroutines in the same address space.
  • An OS Thread takes about 1MB of memory. You can only run a few thousand before crashing your server.
  • A Goroutine takes only 2KB of memory. You can easily run 100,000 Goroutines on a standard laptop simultaneously!

5. Spawning a Goroutine

To run a function concurrently, simply place the keyword go in front of the function call.

Let's look at sequential code first:

go
123456789101112131415161718
package main
import (
    "fmt"
    "time"
)

func count(name string) {
    for i := 1; i <= 3; i++ {
        fmt.Println(name, ":", i)
        time.Sleep(time.Millisecond * 500) // Pause for half a second
    }
}

func main() {
    count("Sheep")
    count("Cows") 
    // It takes 3 seconds total. Sheep finishes, THEN Cows start.
}

Now, let's make it Concurrent!

go
12345678
func main() {
    go count("Sheep") // Spawns a Goroutine and instantly moves to the next line!
    go count("Cows")  // Spawns another Goroutine!
    
    // We MUST pause the main function, otherwise it will exit instantly and kill the Goroutines!
    time.Sleep(time.Second * 2) 
    fmt.Println("Done!")
}

*Output:*

text
1234567
Cows : 1
Sheep : 1
Sheep : 2
Cows : 2
Cows : 3
Sheep : 3
Done!

Notice how they print at the exact same time!

6. The "Main" Goroutine Rule

The main() function is a Goroutine itself. CRITICAL RULE: When the main() Goroutine finishes and reaches its closing brace }, the entire program terminates instantly, destroying all other active Goroutines.

This is why we had to add time.Sleep in the example above. If we didn't, main would spawn the two tasks and immediately close the program before the sheep or cows had a chance to print anything!

7. Visualizing the Goroutine Flow

text
123456789
Main Goroutine starts
      |
      +---- `go count("Sheep")` spawns Goroutine 1 ---(Executes independently)--->
      |
      +---- `go count("Cows")` spawns Goroutine 2 ---(Executes independently)--->
      |
Main Goroutine waits (time.Sleep)
      |
Main Goroutine finishes -> Program Exits (Kills any surviving Goroutines)

8. The Go Scheduler

You don't have to manually assign Goroutines to CPU cores. The Go Scheduler is a genius piece of software built into the Go runtime. It looks at your available CPU cores and rapidly multiplexes thousands of Goroutines across them automatically.

9. Common Mistakes

  • Forgetting to Wait: Using the go keyword but wondering why the program finishes instantly without printing any output. (The main function finished too fast).
  • Using time.Sleep in Production: time.Sleep is great for tutorials, but in the real world, you never know exactly how long a database query or network request will take. Sleeping for an arbitrary amount of time is terrible practice. (We will learn the proper way to wait using WaitGroups and Channels in the next chapters).

10. Best Practices

  • Keep it Lightweight: Feel free to spawn thousands of Goroutines! Go is specifically designed to handle them. For example, a Go web server automatically spawns a brand new Goroutine for every single incoming HTTP request.

11. Exercises

  1. 1. Write a function printNumbers() that prints 1 to 5 with a 100ms sleep.
  1. 2. Write a function printLetters() that prints A to E with a 100ms sleep.
  1. 3. Call both in main() using the go keyword, and add a sleep in main to ensure they finish. Observe the interleaved output.

12. MCQs with Answers & Explanations

Question 1

What is Concurrency?

Question 2

What is a Goroutine?

Question 3

How much memory does a new Goroutine roughly consume?

Question 4

How do you trigger a function to run concurrently in a new Goroutine?

Question 5

What happens when the main() function finishes its last line of code?

Question 6

What component of Go automatically distributes Goroutines across your multi-core CPU?

Question 7

If you run go taskA() and go taskB(), which one will finish first?

Q8. Is time.Sleep() the recommended way to wait for Goroutines to finish in production code? a) Yes b) No, because you cannot predict exactly how long a task will take Answer: b) No.
Question 9

What automatically happens when a Go web server receives an incoming HTTP request?

Q10. Can Goroutines communicate with each other? a) Yes, but we haven't learned how yet b) No, they are strictly isolated Answer: a) Yes. *(Hint: Chapter 20!)*

13. Interview Preparation

Interview Questions:
  1. 1. Contrast Goroutines with traditional OS Threads (Memory footprint, management).
  1. 2. What happens if a Goroutine is running, but the main Goroutine exits?
  1. 3. Explain the difference between Concurrency and Parallelism.

14. Summary

Goroutines are the crown jewel of the Go language. By simply typing the word go, you unlock the full multi-core power of modern processors. However, because they execute independently, they introduce a new problem: synchronization. How do we know when they are done? How do they share data without overwriting each other?

15. Next Chapter Recommendation

Currently, our Goroutines are deaf and blind; they cannot talk to main or to each other. In Chapter 20: Channels in Go, we will introduce the mechanism that allows Goroutines to safely send and receive data between themselves.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·