Lesson F01.1Distributed data processing course / Foundations / Parallelism

What determines a job’s runtime?

Sixteen processes, one disk: why the hourly job stopped speeding up at 63 seconds

13 min read · 10 sections · 5 predictions · Junior
· Verified source figures:Python 3.13 · simulator 0.1 · captured 2026-10-13
Before you start

Basic Python is enough. You do not need to install anything to read this lesson. The monetary costs later in the lesson use illustrative units, not a real currency. The ratios are what matter.

Terms are defined in this margin where they first appear.

01

Why understanding processing costs matters

Let’s consider an Order platform. Any order on such a platform goes through different states. These can be placed, paid, shipped, delivered, or cancelled. Now let’s say, every night, a Python job reads the day’s events, checks their fields, amounts, and timestamps, then counts accepted and rejected records. On average, we get 60 million events (16.2 GB). On a one-process workload, the job takes 20.7 minutes. Peak volumes are much larger, and order volume keeps on increasing, so someone suggests running it on more machines. Will that make the job finish sooner? And is it worth the cost?

To answer these questions, we need to know how much work one event creates, which machine resources do that work, and which resources the processes share.

02

Breaking down the cost of one event

Here is one event from our input:

One event, as the job reads it
{
  "event_id": "ev-000001",
  "delivery_id": "dl-27e4102e32",
  "supersedes_event_id": null,
  "order_id": "ord-00001",
  "customer_id": "cust-0134",
  "event_type": "order_placed",
  "amount_cents": 699,
  "event_time_utc": "2026-03-02T00:08:54.332Z",
  "ingest_time_utc": "2026-03-02T00:09:02.929Z"
}

Processing an event involves up to three types of work:

  1. Disk I/O: Read the event’s data from storage – approximately 270 bytes in our example above.
  2. CPU: Decode the JSON and validate the fields.
  3. Network I/O: Transfer the event if the worker reads it from another machine or storage service.

Let’s estimate the disk-read time. An SSD, which usually reads at 500 MB/s, transfers 500,000,000 bytes per second:

270 ÷ 500,000,000 = 0.00000054 seconds = 0.54 µs.

A microsecond (µs) is one millionth of a second. In our reference benchmark, we tested a Python program called a validator. For each order event, the validator parses the JSON, checks that all nine required fields are present, and verifies values such as the order amount and timestamps. The validator processed 21,154 events in approximately 0.352 seconds. Dividing the total processing time by the number of events gives us an average of 16.63 µs per event. This means the validator can process approximately 60,000 events per second on a single processor core under the benchmark conditions. Importantly, this measures only the time spent parsing and validating events. It does not include reading data from disk or transferring it over a network. We’ll use 20 µs of CPU time per event throughout this lesson for simpler calculations.

For network transfer, a 1 Gbps connection can theoretically transfer about 125 MB per second. At that speed, transferring a 270-byte event takes approximately 2.16 µs.

Below is a Resource cost table for a given 270-byte event.

ResourceTime per recordAssumed rate or cause
CPU: parse and validate20 µsSimplified validator cost
Local SSD read0.54 µs500 MB/s
Hard disk (HDD) read1.80 µs150 MB/s
NVMe disk read0.09 µs3 GB/s
Network transfer2.16 µs1 Gbps, approximately 125 MB/s

CPU validation costs 20 µs per record. Reading the same record from the local SSD costs 0.54 µs.

Pause and predict · P1Commit before you read on

How do they compare?

Fig. 1 · The price of one 270-byte recordSwitch the source to see P2
Local SSD: 20.54 microseconds per record
CPU: parse and validateSimplified validator cost
20 µs
Local SSD read500 MB/s
0.54 µs
Hard disk (HDD) read150 MB/s
1.80 µs
NVMe disk read3 GB/s
0.09 µs
Network transfer1 Gbps ≈ 125 MB/s
2.16 µs
One record, end to end
Local SSD
20.54 µs
CPUSSD readNetwork
CPU ÷ SSD read = 20 ÷ 0.54≈ 37×
Source

For one worker reading from the SSD, CPU work is about 37 times the SSD-read cost. CPU is therefore the dominant part of this workload. That does not mean CPU will always be the bottleneck. If many processes share one disk or network link, the shared resource may limit the whole job.

Now the worker gets its records from a remote source. For this example, keep the source’s 0.54 µs SSD read and add a 2.16 µs network transfer.

Pause and predict · P2Commit before you read on

How much does the modelled per-record cost increase?

03

Latency and throughput

Latency tells us how long it takes to process a single record or an event.
Throughput tells us how many records can be processed per second.

In our reference benchmark, the validator took an average of 16.63 µs to parse and validate one record. For a dataset containing 21,154 records, the total processing time is approximately:

21,154 × 16.63 µs = 0.352 seconds

This means the validator can process approximately 60,000 records per second under the benchmark conditions. Remember two important distinctions:

  • Measured vs. estimated cost: The benchmark measured 16.63 µs per record which is a measured cost, but we use a rounded estimate of 20 µs for simpler and more conservative calculations throughout this lesson — an estimated cost.
  • Processing time vs. total job time: The 16.63 µs measures only the time spent parsing and validating one record. These are processing times of a Job. The Job takes additional time to read data from disk, transfer data over the network when needed, start workers, and coordinate their work.

Add a second identical machine. Each machine processes its own 21,154-record file.

Pause and predict · P3Commit before you read on

What happens to the time spent validating an individual record?

This example scales total throughput, not the speed of one record. To shorten the wall time of a single job, we must split that job’s input. The next example shows why splitting work after a certain point stops helping.

04

Multiple processes, one disk

An hourly validation job processes 24 million events (6.48 GB) on a machine with 32 CPU cores and one HDD. This HDD reads at 150 MB/s. Each process also uses one CPU core. With 8 processes, the job takes 81.4 seconds to complete. To speed things up, the operations team doubles the number of processes to 16.

But will doubling the processes cut the runtime in half?

Pause and predict · P4Commit before you read on

How long does the hourly job take with 16 processes?

At 8 processes, each process has 65.4 seconds of work, longer than the disk floor. The CPU work is the limiting factor in this model. At 16 processes, each process has only 32.7 seconds of work, but the shared disk still needs 43.2 seconds. The disk now sets the pace. More CPU cores cannot make it read the file faster. At 32 processes, wall time actually rises to 71.2 seconds. The disk floor stays the same, while process overhead increases. In our benchmark, the processors are idle for about 62% of the processing phase.

Fig. 2 · Sixteen processes, one HDDTry 8, 16 and 32
16 processes on one HDD: disk-bound, wall 63.2 seconds
24 M events · 6.48 GB · one HDD, 150 MB/s · 16 processesDisk-bound
Process 1
32.7 s work
Process 2
32.7 s work
Process 3
32.7 s work
Process 4
32.7 s work
+ 12 more
same split
Overhead
20.0 s
0 sfloor 43.2 swall 63.2 s
wall(16) =overhead20.0 s+ max(work ÷ N32.7 s,disk floor43.2 s) =63.2 s
Work / process32.7 s
Wall time63.2 s
Idle24%
Cost per run0.84 u
Processes

The bottleneck moved from CPU to disk I/O. Adding more CPU processes no longer helps because all of them depend on the same HDD.

05

Fixing the bottleneck

Instead of adding more processes, we should improve the resource limiting the job’s performance: the disk. Let’s replace the HDD with a faster NVMe disk that can read 3 GB/s. This reduces the minimum time needed to read the entire dataset from 43.2 seconds to approximately 2.2 seconds.

With 16 processes, the job now completes in 50.1 seconds instead of 63.2 seconds, a 21% reduction in runtime. The disk is no longer the bottleneck. In this model, the job becomes CPU-bound again, meaning CPU processing now takes longer than reading the data.

Fig. 3 · The same job on NVMeCompare HDD and NVMe
16 processes on NVMe: CPU-bound, wall 50.1 seconds
24 M events · 6.48 GB · NVMe, 3 GB/s · 16 processesCPU-bound
Process 1
30.1 s work
Process 2
30.1 s work
Process 3
30.1 s work
Process 4
30.1 s work
+ 12 more
same split
Overhead
20.0 s
0 sfloor 2.2 swall 50.1 s
wall(16) =overhead20.0 s+ max(work ÷ N30.1 s,disk floor2.2 s) =50.1 s
Work / process30.1 s
Wall time50.1 s
Idle0%
Cost per run0.87 u
ProcessesDisk
ProcessesWork per processDisk floorWall timeCost per run
860.3 s2.2 s76.3 s0.66 units
1630.1 s2.2 s50.1 s0.87 units
3215.1 s2.2 s43.1 s1.49 units

But faster hardware costs more. The HDD drive mentioned above is billed at 3.0 units per core-hour; the NVMe machine at 3.9 units per core-hour.

For 16 processes, the NVMe run costs: 16 × 50.1 ÷ 3,600 × 3.9 ≈ 0.87 units.

The corresponding HDD run costs about 0.84 units. The NVMe option is roughly 4% more expensive using these rounded prices, but completes about 21% sooner. Is this additional cost justifiable? It depends on the business needs and what a faster result is worth.

Another option is reducing the bytes read through compression or a more efficient file layout. How to design that layout belongs to Data Modelling & Storage Design. Here, the important question is whether reading those bytes is actually the bottleneck.

06

What this benchmark shows and its limitations

This benchmark demonstrates three important lessons:

  1. Understand where processing time goes: Measuring the CPU, disk, and network costs of processing each record helps identify potential bottlenecks.
  2. Shared resources limit performance: When multiple processes share the same disk, adding more CPU cores cannot reduce the minimum time required to read the data.
  3. More processes don’t always mean faster execution: Once a resource becomes the bottleneck, adding processes may increase overhead and make the job slower.

Limitations of the benchmark

The simulation run makes a few simplifying assumptions:

  • Equal workload: Every process handles the same amount of work. We’ll explore uneven data distribution in F02.
  • Simplified resource costs: The model uses fixed processing costs, while real systems may read data and perform computations simultaneously.
  • No failures: The model doesn’t account for task failures or retries. We’ll cover these in F04.

Note: These results illustrate how bottlenecks affect performance. Always measure your actual CPU, disk, network, and workload behaviour before making optimisation decisions.

07

How to spot a shared-resource bottleneck

When multiple processes share a resource, such as a disk or network connection, adding more processes may stop improving performance. Always look for these three warning signs:

  1. Less work per process, but no faster execution: Each process handles less work, yet the processing phase stops getting shorter.
  2. The shared-resource limit is reached: The processing phase cannot drop below the minimum time required by the shared resource.
  3. Total runtime stops improving: Adding more processes produces little improvement or even increases the job’s runtime.

In real systems, similar signs include:

  • Throughput stops increasing as more workers are added.
  • Disk or network utilisation remains high, indicating a saturated resource.
  • CPU utilisation stays low because processes are waiting for data rather than performing computations.
08

What to check before adding workers

Before increasing the number of workers, ask yourself four questions:

011 · What does it cost to process one record?

Estimate the CPU time, disk reads, and network transfers required.

022 · Which resources do the workers share?

Identify shared disks, network connections, or services that could become bottlenecks.

033 · What is the minimum processing time?

Calculate how long the shared resource needs to handle the entire workload, regardless of the number of workers.

044 · What is the overhead of adding workers?

Consider startup, coordination, and communication costs. We’ll explore these in F01.2.

09

Check your understanding, then run the model

The nightly job has 60 million events (16.2 GB). Compare two ways to provide 16 CPU cores:

  • Option 1: One 16-core machine, with the file on its local SSD.
  • Option 2: Sixteen one-core machines, each with its own SSD and one-sixteenth of the file.

The CPU work per record is the same.

Pause and predict · P5Commit before you read on

Which option finishes sooner in the model?

Try it in the workbench. The L-F01 simulator will let you reproduce the hourly result:

Run it
python -m sim run --job hourly_validate --cluster one_node_hdd --workers 16

Check that the disk floor and processing phase are both 43.2 seconds. Then change --workers 16 to --workers 32. Watch what happens to work per process and wall time.

The article itself requires no installation. Record your answers to P01–P05 before viewing their reveals.

Note: The workbench is a small Python repository you clone and run on your laptop (Python 3.11, nothing else); it opens at /learn/distributed/parallelism.

10

Summary

Every record requires processing resources, including CPU time, disk reads, and sometimes network transfers. Understanding these costs helps identify bottlenecks and determine whether adding more workers will actually improve performance.

In our hourly validation example:

  • A single HDD needs at least 43.2 seconds to read the entire dataset.
  • With 16 processes, the shared disk becomes the bottleneck, and the job takes 63.2 seconds
  • Upgrading to faster storage reduces runtime by approximately 21%, while increasing cost by only 4%.

More workers don’t always mean faster execution. Identify the bottleneck first, then optimise the resource that actually limits performance.

Where it shows up

Interview form: “We doubled the cores and the job did not get faster. Why?” Start with “which part of the machine set the pace?” Production symptom: throughput flat across process counts, a disk or link at 100%, processors idle at a steady fraction. In Spark the same floor appears as executors on one node sharing its disk (S04).

Sources and reproducibility. Figures reproduced from reference model sim 0.1, Python 3.13.16, captured 2026-10-13. Fixture: orders_s0_small.jsonl, SHA-256 prefix 5ac4be13…, mean size 269.8 bytes/line. Validator benchmark: 16.63 µs/record, parse + contract validation, 2.1 GHz Xeon, best of five. Profiles: hourly_validate, nightly_validate, one_node_hdd, one_node_nvme, one_node_ssd, and lab_cluster. The price-list approach is inspired by Peter Norvig’s Teach Yourself Programming in Ten Years; the figures here come from the module’s model or measurements, not Norvig’s table.

Ask Colearn about this lesson

3 of 3 free questions left

Ask why a second machine leaves each event no faster, or how to tell a CPU-bound job from an I/O-bound one.

Instant answers, grounded in the same verified material the diagnostic grades against.

Why didn't adding a second machine make each event faster?

Each event still needs the same validation work. A second machine can increase total throughput without changing per-record validation latency. One job finishes sooner only when its work can be divided efficiently.

How do I tell whether a job is CPU-bound or I/O-bound?

Estimate the resource cost per record, then identify what the workers share. In our reference workload, CPU validation costs about 37 times a local SSD read for one worker. But with 16 workers sharing one HDD, the disk's 43.2-second floor becomes the limit.

Don’t paste credentials, personal data, or confidential production records.
Related

L-F01 worker-cost simulator (planned) · F01 module diagnostic

Up next · Lesson F01.2Why adding more workers can make a job slower

We'll examine fixed overhead, the serial fraction, and how to choose a useful worker count.