Skip to content
BytePatterns

Sizing a Thread Pool

Concurrency: lesson 13 of 15

More threads stop helping the moment the work stops waiting.

Lesson 13 of 15 · 5 min

Sizing a Thread Pool

Step 1 of 9

Eight tasks: four long, four short. Twenty units of work, and the longest single task is four.

The Idea

A pool size is a bet about where the bottleneck is. CPU-bound work saturates at roughly the core count; extra threads only add context switches. IO-bound work spends its time blocked, so many more threads fit. Either way the longest single task is a floor nothing can go below.

Real-World Example

A pizzeria with one oven. Hiring a fourth chef speeds up prep, which was the queue. Hiring a tenth does not, because the oven never got faster and the kitchen now has a traffic problem.

The Code

def makespan(tasks, workers):
    free = [0.0] * workers                 # when each worker is next idle
    for cost in sorted(tasks, reverse=True):
        first = min(range(workers), key=lambda w: free[w])
        free[first] += cost
    return max(free)

jobs = [4, 4, 4, 4, 1, 1, 1, 1]            # 20 units of work, longest is 4
for n in (1, 2, 4, 8, 16):
    print(n, makespan(jobs, n))
# 1 20.0 / 2 10.0 / 4 5.0 / 8 4.0 / 16 4.0 -- the longest task is the floor

Python

Your turn

Fill in the blank.

def makespan(tasks, workers):
  free = [0.0] * workers
  for cost in sorted(tasks, reverse=True):
      free[min(range(workers), key=lambda w: free[w])] += cost
  return max(free)

print(makespan([3, 3, 3], ___))   # 3.0

Mini quiz

1 / 3

For CPU-bound work, a good starting pool size is:

New lessons land every few weeks

Leave an address and we will tell you when the next one is up. That is the only reason we will use it.

One address, stored so we can email you. Nothing else, ever.