Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Splitting work across processes

After this lesson: I can split a job into chunks, run them in separate processes and merge the answers.

60 min lesson2 commandsParallel computing lab: how a GPU thinks, without a GPU, in JupyterLab

How to split a job between processes

To use several processors, you split one job into chunks, give each chunk to a separate worker and merge the answers. Splitting a job well is the skill behind every parallel program, from a laptop to a GPU.

A shop wants the total of a day's 40,000 orders. Four workers can each add a quarter of them, then one more step adds the four answers.

By the end of this lesson

Note

I can split a job into chunks, run them in separate processes and merge the answers.

Key words

WordWhat it means
Processa running program with memory of its own
Threada worker inside a process that shares its memory
Chunkone share of the data given to one worker
Partial resultthe answer for one chunk alone
Mergecombine partial results into the final answer
Poola set of workers that take chunks in turn

The cells students fill in are left blank in this preview.

A job is split into chunks and merged

Chunks are shares of the data, cut so that no item is in two chunks and none is left out. Each worker gives a partial result for its own chunk.

A final step merges the partial results. For a sum, merging is adding. Cutting the data and merging the answers cost time, and both are serial.

Worked example: 12 totals in 3 chunks

ChunkItemsPartial sum
05, 8, 3, 925
14, 7, 6, 219
210, 1, 8, 524
Mergeadd the partial sums68

The cells students fill in are left blank in this preview.

Run the split and the merge

Code: python
# Cut 12 order totals into 3 chunks, add each chunk, then merge.
totals = [5, 8, 3, 9, 4, 7, 6, 2, 10, 1, 8, 5]
chunks = [totals[0:4], totals[4:8], totals[8:12]]
partials = []
for chunk in chunks:
    partials.append(sum(chunk))
print("chunks:", chunks)
print("partial sums:", partials)
print("merged:", sum(partials), "in one piece:", sum(totals))
# Cut the list into 2 chunks of 6 instead, then run again.

Processes have their own memory, threads share it

A process is a running program with its own memory. A thread runs inside a process and shares that memory.

Standard Python lets only one thread run Python code at a time. So for work that needs the processor, Python programs use several processes. Each has its own copy of the data and its own answer to send back.

A pool keeps the chunks in order

The lab's chunks.py cuts the numbers 1 to 40 into four chunks of ten and gives them to a pool of two workers. A worker that finishes takes the next chunk.

The partial sums come back in chunk order, 55, 155, 255 and 355, whichever worker finished first. Their sum is 820, the same as summing the whole list in one piece.

Run the chunked sum

Command
docker exec jupyter python3 steps/chunks.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Cut ten numbers into two chunks

Command
docker exec jupyter python3 -c "d = list(range(1, 11)); print(d[0:5], d[5:10])"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Not every answer merges by adding

A sum merges by adding. An average does not: the average of the chunk averages is wrong when the chunks differ in size.

Each chunk must send back what the merge needs. For an average that is the sum and the count. The example below shows the wrong and the right way.

Run the two ways to merge

Code: python
# The average of chunks is NOT the average of the chunk averages.
chunk_a = [10, 20, 30, 40]
chunk_b = [100]
wrong = (sum(chunk_a) / len(chunk_a) + sum(chunk_b) / len(chunk_b)) / 2
right = (sum(chunk_a) + sum(chunk_b)) / (len(chunk_a) + len(chunk_b))
print("average of the averages:", wrong)
print("sum and count merged:", right)

A common mistake

Warning

Many people think splitting a job is free. Cutting the data and merging the answers are serial work, and a process needs its copy of the data. Too many tiny chunks can cost more than they save, so keep each chunk big enough to be worth sending.

About this lab and its source: Parallel computing lab: how a GPU thinks, without a GPU, in JupyterLab

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.