Skip to content

9/32 · 5 min

Choosing between the two

Both give concurrency. They differ in what is shared, and everything else follows from that.

What is shared

ProcessesThreads
Memoryseparateshared
Open filescopied at forkshared
Creation costhigherlower
Switch costhigher, TLB flushedlower
One crashesothers surviveusually the whole process dies
Communicationneeds a mechanisma variable
Data races possiblenoyes

The last two rows are the same fact seen twice. Shared memory makes communication free and correctness hard.

When processes are right

Isolation matters. A browser puts each tab in its own process so a crash in one does not take the window with it, and so a compromised page cannot read another site's memory.

Fault tolerance. A supervisor restarting a crashed worker is only possible if the crash was contained.

Python, specifically. The global interpreter lock means threads do not run Python bytecode in parallel, so multiprocessing is the answer for CPU bound work and threading only helps when the work is I/O bound.

When threads are right

Shared state is the point. An in memory cache that every request reads is natural with threads and awkward across processes.

Many short lived units of work. Creating a thread is far cheaper than a process.

The third option

Neither, for I/O bound work. A single thread with an event loop handles thousands of concurrent connections, because each one is mostly waiting, and waiting does not need a thread of its own.

code
10,000 connections, thread each  ->  10,000 stacks, constant switching
10,000 connections, event loop   ->  one stack, one thread, no switching

This is what Node.js does by default, what Go does with goroutines multiplexed onto a few threads, and what async frameworks in Python and Rust do.

The rough rule

Work isUse
CPU boundone process or thread per core, no more
I/O boundasync, or many threads
Needs isolationprocesses
Needs shared statethreads, with locks

More threads than cores does not speed up CPU bound work. It adds switching to the same total amount of computation.