Processes vs Threads: A Beginner's Guide With Real Examples

Learn the real difference between processes and threads, how the operating system schedules them, when to pick one over the other, and why your browser uses both at the same time.

10 min read

Processes and threads are the two ways an operating system runs work in parallel — and confusing them is one of the most common mistakes in concurrent programming. A process is a fully isolated running program with its own memory; a thread is a lightweight unit of execution that shares memory with other threads inside the same process. Pick the wrong one and you get either a memory disaster, a debugging nightmare, or a 10x performance regression.

This guide explains both in plain English, walks through where each shines (and where each ruins your week), and gives you a clear decision tree.

The One-Line Difference

A process has its own private memory; a thread shares memory with other threads in the same process. Everything else — speed, safety, debugging difficulty, scaling — flows from that single fact.

If two units of work need to share data quickly, threads. If they need to be isolated and crash-safe, processes.

How Processes Work

When you launch an app, the OS creates a process: a fresh virtual address space, its own file descriptors, its own environment variables. Two processes cannot see each other's memory unless they explicitly set up shared memory or pipes. If one crashes, the OS reaps it and the others keep running.

Processes are expensive to create — the OS has to set up page tables, copy environment, allocate kernel structures. Modern Linux can create maybe 10,000 processes per second per core. They are also expensive to switch between, because the CPU has to flush caches and reload the page table.

But they are safe. A bug in one process cannot corrupt another. This is why Chrome runs each tab as its own process: a malicious page cannot read your banking tab's memory.

How Threads Work

Inside a single process, you can create multiple threads. Each thread has its own stack and CPU registers, but they all share the same heap, the same global variables, the same file descriptors. Switching between threads is cheap — no page-table reload, no cache flush.

Threads make sharing data trivial. They also make sharing data dangerous: two threads writing to the same variable without coordination is a race condition, and race conditions are the most painful bugs in software. You will need locks, atomics, channels, or the language's own concurrency primitives to stay sane.

Side by Side at a Glance

DimensionProcessThread
MemoryPrivateShared with siblings
Crash blast radiusJust this processWhole process
Creation costExpensive (ms range)Cheap (μs range)
Switching costExpensiveCheap
Data sharingPipes, sockets, shared memDirect memory access
Concurrency hazardsFew (isolation)Many (races, deadlocks)
Best forIsolation, security, fault toleranceTight-coupled parallelism, low latency

A Worked Example: Chrome Uses Both

Chrome is the textbook case. Each browser tab is a separate process (renderer process). This is why a runaway JavaScript loop in one tab does not freeze your other tabs and why Spectre-style attacks are mitigated.

Inside each renderer process, dozens of threads do specific jobs: the main thread runs JS, the compositor thread paints frames at 60 Hz, worker threads handle image decoding. They share the page's DOM data structures directly because they live in the same memory space.

This hybrid is the modern playbook: processes for isolation, threads for parallelism within a unit of isolation.

When to Pick Threads

Pick threads when:

  • The work units share lots of data and would be slow to copy across processes.
  • Latency matters and you cannot afford process creation/IPC cost.
  • You need many concurrent units (web servers handling thousands of connections).
  • You are I/O-bound and want a single process to keep the CPU busy.

Examples: a web server like Tomcat, a game engine's audio + physics + rendering, a database query engine running parallel scans.

When to Pick Processes

Pick processes when:

  • Crashes must be contained (browsers, plugin systems, untrusted code).
  • You need real CPU parallelism in a language with a Global Interpreter Lock (Python's CPython, Ruby).
  • The work units are loosely coupled and rarely need to talk.
  • Security boundaries matter (sandboxes, multi-tenant systems).

Examples: Chrome's per-tab isolation, Postgres's per-connection backend processes, Python multiprocessing for CPU-bound work, Nginx worker processes.

The Python Special Case

Python's CPython interpreter has a GIL (Global Interpreter Lock) that allows only one thread to run Python bytecode at a time per process. So:

  • For I/O-bound Python work (web requests, file I/O), threads are great — they release the GIL while waiting.
  • For CPU-bound Python work (number crunching, image processing), threads do not help — use multiprocessing or move the hot path to NumPy/Cython.

In 2026 the no-GIL build (PEP 703) is finally stable opt-in, but most production deployments are still on the GIL build. Plan accordingly.

pypy
# CPU-bound: threads useless, processes work
from multiprocessing import Pool
with Pool(8) as p:
    results = p.map(crunch_numbers, big_dataset)

Common Mistakes Beginners Make

  • Spinning up one thread per task forever. Use a thread pool. Unbounded threads exhaust memory fast.
  • Sharing mutable data between threads without locks. A race condition will appear in production a week later.
  • Using multiprocessing for trivial work. The startup cost (~50ms per process) destroys speedup on small jobs.
  • Mixing threads and fork(). Forking a multi-threaded process in Linux is officially a footgun. Spawn instead.
  • Assuming "more threads = faster". Past your physical core count, you mostly add context-switch overhead.

Quick Reference

You need...Default answer
Isolated, crash-safe unitsProcesses
Cheap parallelism with shared stateThreads
Real CPU parallelism in CPythonProcesses
Handle 10k network connectionsThreads (or async)
Sandbox untrusted codeProcesses
Low-latency in-game systemsThreads
Rune AI

Rune AI

Key Insights

  • Process = private memory, crash-safe, expensive to create.
  • Thread = shared memory, cheap, dangerous without locks.
  • Use processes for isolation; use threads for tight-coupled parallelism.
  • Python's GIL means threads do not help CPU-bound work — use multiprocessing.
  • The modern Chrome-style template is both: process per isolation boundary, threads inside each.
RunePowered by Rune AI

Frequently Asked Questions

What is a "green thread" or "fiber"?

user-space thread scheduled by the language runtime, not the OS. Cheaper than OS threads, no kernel involvement. Goroutines in Go, virtual threads in Java 21+, async tasks in Rust/JS are all flavours of this.

Are async/await and threads the same?

No. `async/await` is *single-threaded concurrency* — one thread cooperatively switches between many tasks while waiting on I/O. Threads are *preemptive parallelism* — the OS yanks the CPU between them.

How many threads should my web server use?

common starting point is `2 × CPU cores` for CPU-bound, much higher (hundreds) for I/O-bound on traditional servers. Async runtimes flip this — one thread per core is often optimal.

Why do databases prefer processes?

Postgres uses one process per connection for fault isolation: a crashing connection cannot corrupt the others. MySQL uses threads for lower per-connection cost. Both work; both have trade-offs.

Are threads dying because of async?

No. Threads remain the right tool for CPU-parallel work and many concurrent independent units. Async dominates I/O-bound network work. They coexist.

Conclusion

Processes and threads are the two halves of OS-level concurrency, and the one-line rule covers 90% of decisions: use processes for isolation and crash safety, use threads for cheap parallelism with shared memory. Real systems combine them — Chrome's tabs-as-processes plus threads-per-tab is the modern template. Once you internalise the trade-off, concurrent code stops being scary and becomes another design choice. The scariest bugs in your career will be race conditions; the boring fix is to copy what Chrome does.