Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 17

Threads vs. Processes: Concurrency and Parallelism

Recommended resources

Hello! Welcome back.

In our last lesson, we established that a process is the fundamental unit of execution in an operating system. It's a program loaded into memory, complete with its own private virtual address space, file descriptors, and a Process Control Block (PCB) to manage it all. We noted that creating a process is a relatively "heavy" operation for the OS.

This begs a critical question for backend development: If a web server needs to handle hundreds or thousands of simultaneous client connections, is creating a new process for every single one a viable strategy? The overhead would be immense. This is where a more lightweight unit of execution becomes essential.

Today's Goal: We will dive into this lighter-weight concept. The learning outcome for this lesson is to explain the difference between threads and processes, and how they relate to concurrency and parallelism. This is a cornerstone concept for understanding how modern servers efficiently handle massive workloads.

What is a Thread?

If a process is like a self-contained company, a thread is like an employee within that company. A thread is the smallest sequence of instructions that can be managed independently by the operating system's scheduler. Multiple threads can exist within a single process, working together to achieve the process's goal.

Let's start with a video that uses this exact analogy to build a strong mental model.

What is a Thread? | Threads, Process, Program, Parallelism and Scheduler Explained | Geekific

The video 'What is a Thread?' by Geekific provides an excellent analogy, comparing a process to a company and threads to its employees. This will help clarify their relationship and roles.

Watch from the beginning up to 04:05. Focus on how employees (threads) have their own resources (stack, registers) but also use shared company resources (heap memory, code).

As the video explained, the key to understanding the process/thread difference lies in what they own versus what they share.

  • A process encapsulates all the resources needed to run a program. When you start your Django app, the OS creates a process with its own complete, isolated virtual address space (code, data, heap, stack) and its own set of file descriptors.
  • A thread lives inside a process. It gets its own execution context but shares most of the process's resources with other threads in the same process.

To get an expert, technical breakdown of what's shared and what's unique, let's turn to a classic source.

What is the difference between a process and a thread?

This Stack Overflow question contains a highly-cited answer that quotes from the famous operating systems textbook, 'Modern Operating Systems' by Andrew S. Tanenbaum. It provides a definitive table that perfectly distinguishes per-process items from per-thread items.

Read the answer that begins with 'First, let's look at the theoretical aspect.' It's about halfway down the page. Focus on the distinction between a process for 'resource grouping' and a thread for 'execution,' and pay close attention to the table that follows.

Let's summarize that crucial table:

Shared (Per Process) Owned (Per Thread)
Address space Program Counter (PC)
Global variables Registers
Heap memory Stack
Open files / Sockets State (running, waiting...)
Child processes
Accounting info

This distinction has profound consequences:

  1. Creation Cost: Threads are "lightweight" because creating one doesn't require allocating a new virtual address space or duplicating resources like file tables. The OS only needs to create a new stack and execution context. Processes are "heavyweight" because they require a full duplication of the parent's resources (or setting them up from scratch).
  2. Communication: Since threads within a process share the same memory (heap), they can communicate and share data easily and quickly. Inter-Process Communication (IPC) is far more complex and slower, as the OS must mediate to protect their isolated memory spaces.
  3. Fault Isolation: The isolation of processes is a strength. If one process crashes, it generally doesn't affect others. However, because threads share memory, a bug in one thread (like writing to an invalid memory address) can corrupt the data of other threads and crash the entire process. The Geekific video explores this using Google Chrome's architecture as an example, where each tab runs as a separate process for better stability.

Concurrency vs. Parallelism

Now that we understand threads and processes, let's clarify two closely related but distinct terms: concurrency and parallelism. They are not interchangeable.

  • Concurrency is about dealing with multiple tasks at once. It's a structural concept. On a single CPU core, the OS can run one task, pause it, switch to another task, run it for a bit, and switch back. This happens so fast it creates the illusion of simultaneous execution. It's about managing interleaved tasks.
  • Parallelism is about doing multiple tasks at once. It's a hardware concept. To achieve true parallelism, you need a system with multiple CPU cores. Each core can execute a separate task at the exact same time.
Concurrency vs. Parallelism
This image illustrates the core difference. Concurrency (left) involves a single core interleaving Task 1 and Task 2. Parallelism (right) involves two separate cores executing Task 1 and Task 2 simultaneously.

This next video provides a very clear and concise explanation of this difference and, importantly, connects it to the types of workloads we see in backend systems.

Concurrency vs. Parallelism

The video 'Concurrency vs. Parallelism' by The Coding Gopher is excellent for solidifying these definitions. It also introduces the critical concepts of I/O-bound and CPU-bound tasks, which determine whether concurrency or parallelism is more beneficial.

Watch from 00:53 to 05:21. Pay close attention to: The core definitions of concurrency (interleaved) and parallelism (simultaneous). Why concurrency is effective for I/O-bound workloads (like web requests). Why parallelism is better for CPU-bound workloads (like heavy computation).


Application to Backend Servers

As you just saw, understanding this is not just academic; it directly influences how we design and build servers.

I/O-Bound Workloads and Concurrency

Most web applications are I/O-bound. When your Django view receives a request, it might:

  1. Parse the HTTP request (CPU work, very fast).
  2. Query the database (I/O work, slow).
  3. Call an external API (I/O work, slow).
  4. Render a template (CPU work, fast).
  5. Send the HTTP response (I/O work, slow).

The process spends most of its time waiting for the database or network. A concurrent server can use this waiting time productively. While one thread is blocked waiting for a database query to return, the OS can schedule another thread to handle a completely different incoming request. This is why multi-threaded servers are so effective for web applications—they maximize CPU utilization by not letting it sit idle during I/O waits.

CPU-Bound Workloads and Parallelism

Imagine you were building a service that takes a video and compresses it, or trains a machine learning model. These are CPU-bound tasks. The limiting factor is the raw computational power of the CPU. Here, true parallelism is what you need. You would want to split the work across multiple CPU cores to finish the job faster. Using processes (via Python's multiprocessing module) is often the strategy here, as it sidesteps Python's Global Interpreter Lock (GIL) and allows different Python interpreters to run on different cores simultaneously.

This article summarizes the benefits of threading, reinforcing these points.

6.4: Threads :: Operating Systems and C

The article from Kuleuven provides a great summary of the benefits of using multiple threads, which directly relate to the concepts of concurrency and responsiveness in I/O-bound applications.

Read the sections 'What’s in a thread ?' and 'Why would we want multiple threads ?'. This will reinforce the resource sharing model and summarize the key advantages (Responsiveness, Resource sharing, Economy, Scalability).


Conclusion

In this lesson, we demystified the relationship between processes, threads, concurrency, and parallelism—concepts that are fundamental to modern computing and essential for building high-performance backend systems.

Key Takeaways:

  • Processes are isolated execution environments with their own memory space. They are heavyweight.
  • Threads are lightweight execution units within a process. They share memory (heap, code, files) but have their own stack and registers.
  • Concurrency is about managing multiple tasks by interleaving them. It can happen on a single CPU core and is ideal for hiding the latency of I/O-bound work.
  • Parallelism is about executing multiple tasks simultaneously. It requires multiple CPU cores and is ideal for speeding up CPU-bound work.
  • Most web server tasks are I/O-bound, making concurrency through threading a highly effective model for handling many simultaneous clients.

Preview of the Next Lesson:

We've established that concurrency is achieved by the OS rapidly switching between tasks (threads or processes). But this switching isn't free. In the next lesson, we will explore what context switching is and its performance implications for servers. Understanding the cost of this switching is the next step in appreciating why certain server architectures are designed the way they are.