liveBook · Manning

Fork-join model

As explained in Grokking Concurrency

The fork/join pattern divides a problem into independent subtasks, processes them concurrently, and combines their results into the overall solution.

Imagine four people counting four piles of ballots. Each person works independently, and one person combines the totals at the end. That is the fork/join model: split a problem into independent subtasks, process them concurrently, and combine their results into one solution. section 7.7

The pattern follows two main stages:

  • Fork the data or problem into smaller chunks that can be processed independently. section 7.7
  • Run the chunk-processing tasks concurrently, scaling horizontally when more processing resources are available. section 7.7
  • Join the results by waiting for dependent tasks to finish and combining their outputs into the original solution. section 7.7

The independent work can run in parallel, but the final combination is sequential because it depends on every earlier result. The pattern is useful when data can be divided relatively independently; task number and task size still determine whether the decomposition is well matched to available processing resources. section 7.10 section 7.7

Counting election votes

Divide a large pile of votes into four smaller piles. Four workers count each pile, producing four candidate summaries. After all workers finish, combine those summaries to calculate the final count for every candidate. section 7.7

# Chapter 7/count_votes/count_votes_sequential.py
import typing as T
import random

Summary = T.Mapping[int, int]

def process_votes(pile: T.List[int]) -> Summary:
    summary = {}
    for vote in pile:
        if vote in summary:
            summary[vote] += 1
        else:
            summary[vote] = 1
    return summary

if __name__ == "__main__":
    num_candidates = 3                                                     #1
    num_voters = 100000                                                    #1
    pile = [random.randint(1, num_candidates) for _ in range(num_voters)]  #1
    counts = process_votes(pile)
    print(f"Total number of votes: {counts}")

Use the Python vote-counting listing as a sequential baseline before comparing it with the concurrent fork/join version. section 7.7

How Grokking Concurrency covers it

How deep it goes
Explains the fork and join stages, parallel-versus-sequential work, and task granularity without descending into runtime internals.
Examples
Uses ballot piles, staff members, candidate summaries, and Python vote-counting implementations as concrete examples.
What it assumes
Assumes basic concurrent-programming and problem-decomposition ideas while teaching the fork and join steps directly.
What you can do after
Apply it to split independent data chunks, process them concurrently, and combine their results.
How it connects
Connects fork/join with decomposition, data decomposition, task granularity, pipeline processing, map, and map/reduce patterns.

Also explained in

Compare how 2 books explain fork-join model →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Grokking Concurrency. The section links point to the parts of the book it draws on.