Go Lesson 31 – Intro to concurrency | Dataplexa

Introduction to Concurrency in Go

Concurrency is one of Go’s most powerful features and a key reason why Go is widely used for backend systems, cloud platforms, and high-performance servers.

In this lesson, you will understand what concurrency is, why it matters, and how Go approaches concurrency differently from many other programming languages.


What Is Concurrency?

Concurrency means handling multiple tasks at the same time. These tasks may not run at exactly the same instant, but they make progress independently and overlap in execution.

For example:

  • Handling multiple HTTP requests on a server
  • Processing user input while loading data
  • Downloading files while updating the UI

Concurrency vs Parallelism

Concurrency and parallelism are related but not the same.

  • Concurrency: Managing multiple tasks at once
  • Parallelism: Executing multiple tasks at the same exact time

Concurrency is about structure and design, while parallelism depends on hardware (multiple CPU cores).


Real-World Analogy

Imagine a restaurant kitchen:

  • A single chef cooking multiple dishes by switching between tasks is concurrency
  • Multiple chefs cooking different dishes at the same time is parallelism

Go is designed to handle both efficiently.


Why Go Is Excellent for Concurrency

Go was designed with concurrency as a first-class feature. Instead of complex thread management, Go provides lightweight concurrency tools.

  • Simple syntax
  • Low memory overhead
  • Scales efficiently
  • Built-in concurrency primitives

The Main Function and Blocking

Before introducing concurrency, let’s understand how a normal Go program runs.

package main

import "fmt"

func main() {
    fmt.Println("Task 1 started")
    fmt.Println("Task 1 finished")
}

This program runs line by line, blocking until each statement completes.


Introducing Goroutines (Conceptual)

A goroutine is a lightweight unit of execution managed by the Go runtime.

Think of goroutines as extremely lightweight threads. You can create thousands of them without heavy resource usage.

Goroutines allow functions to run concurrently.


Creating a Goroutine

To start a goroutine, prefix a function call with the keyword go.

go myFunction()

This tells Go to run the function concurrently.


Simple Goroutine Example

package main

import (
    "fmt"
    "time"
)

func printMessage() {
    fmt.Println("Hello from goroutine")
}

func main() {
    go printMessage()
    time.Sleep(time.Second)
    fmt.Println("Main function finished")
}

Here, the goroutine runs concurrently with the main function. The sleep ensures the program does not exit before the goroutine executes.


Why Sleep Is Not a Good Solution

Using time.Sleep to wait for goroutines is unreliable. It depends on timing and can break under load.

Go provides better synchronization tools, which you will learn in upcoming lessons.


Concurrency in Real Applications

Concurrency is used everywhere in modern Go applications:

  • Web servers handling multiple clients
  • Background job processing
  • Microservices communication
  • Data pipelines

Common Beginner Mistakes

  • Forgetting that goroutines run asynchronously
  • Program exiting before goroutines complete
  • Accessing shared data without synchronization

Best Practices

  • Keep goroutines small and focused
  • Avoid shared mutable state
  • Use channels for communication
  • Use synchronization primitives when required

Practice Exercises

Exercise 1

Create a goroutine that prints a message while the main function prints another message.

Exercise 2

Modify the program to start multiple goroutines.


What’s Next?

In the next lesson, you will learn about Goroutines in Depth and how to use them effectively in real-world applications.