runtime
189 / 250
lesson 189 Threading & Multiprocessing · advanced

Processes: parallel work, separate memory

Each process has its own interpreter, its own memory and its own GIL, so CPU-heavy Python really runs on several cores at once. The price: everything sent to a process and back is copied by pickling.

Read and diagnose: this can't run in the browser, so you'll read real code and output and answer questions about it.

You'll be able to
  • Explain why processes, not threads, speed up CPU-bound Python on standard CPython
  • Know what crosses a process boundary: pickled arguments and results; functions by name
  • Split work into chunks, map a top-level function over them, and combine the partial results
The idea

Threads share one interpreter and its GIL, so pure-Python computation in threads runs one thread at a time. A process is a whole separate Python interpreter, with its own memory and its own GIL, so eight processes can compute on eight cores at once. concurrent.futures.ProcessPoolExecutor gives processes the same submit/map interface as the thread pool (“Executors and futures”).

Processes don't share memory. Arguments travel to the worker and results travel back as bytes made by pickle, Python's object serializer. That has consequences you can see right here, because pickling works in this page even though starting processes doesn't.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · What survives the trip to another process
import importlib
import pickle

with open("fares.py", "w", encoding="utf-8") as f:
    f.write("def zone_total(rows):\n    return sum(row['fare'] for row in rows)\n")
importlib.invalidate_caches()
from fares import zone_total

job = (zone_total, [{"fare": 40.8}, {"fare": 7.2}])
data = pickle.dumps(job)
func, rows = pickle.loads(data)
print(func is zone_total, func(rows), rows is job[1])
try:
    pickle.dumps(lambda rows: len(rows))
except pickle.PicklingError:
    print("PicklingError")
example-2.py · A process pool in this page
from concurrent.futures import ProcessPoolExecutor

with ProcessPoolExecutor(max_workers=2) as pool:
    print(pool.submit(len, "SPO-11681").result())

Process pools work best with a few big jobs: each job pays for pickling its data and its result, and starting the worker processes takes time. So split the input into one chunk per worker, map a top-level function over the chunks, and combine the partial results in the parent. The example runs that shape with the built-in map; on a computer you replace map with pool.map.

example-3.py · Count pickups per zone in chunks
from collections import Counter

def count_zones(lines):
    counts = Counter()
    for line in lines:
        counts[line.split(",")[1]] += 1
    return counts

def chunked(items, size):
    return [items[i:i + size] for i in range(0, len(items), size)]

lines = [f"{16126 + i},{(i * 7) % 5}" for i in range(20)]
# On a computer, under the __main__ guard: with ProcessPoolExecutor() as pool: partials = list(pool.map(count_zones, chunked(lines, 6)))
partials = list(map(count_zones, chunked(lines, 6)))
total = Counter()
for part in partials:
    total += part
print(len(partials), dict(sorted(total.items())))

When to use processes: CPU-heavy pure-Python work (parsing, simulation, image or text processing) that can be split into independent chunks. When not to: small jobs (start-up and pickling cost more than the work), jobs needing large shared data (it is copied to every worker), and waiting-bound work (threads or asyncio are lighter). Mistakes to avoid: lambdas or nested functions as the worker; expecting a worker's changes to globals to be visible in the parent; and forgetting the __main__ guard.

Review
  • Processes have separate memory and separate GILs: CPU-bound Python runs in parallel.
  • Arguments and results are pickled copies; worker functions must be top-level; never unpickle untrusted data.
  • Few big chunks, a top-level worker, combine partial results; guard the entry point with __main__.
  • Next: measured numbers that show when threads or processes actually pay off.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Processes: parallel work, separate memory — Threading & Multiprocessing · Runtime