Concepts / Task Division in Parallel Processing

Task Division in Parallel Processing

Equal-sized subproblems do not guarantee equal completion times, because the work inside each piece and the speed or availability of each processor can differ.

  • Programming

A Fair-Looking Split of the Work

A common first instinct when speeding up a job with several processors is to cut it into pieces of the same size and hand one piece to each processor. The reasoning seems sound. If every piece is the same amount of work, every processor should finish at the same moment, and the total time should drop roughly in proportion to the number of processors. Many beginners never question this belief. This article examines why it fails and what a better strategy looks like.

What do you think happens?

Four processors each receive a piece of exactly the same size. One piece contains much harder computation than the others. What happens to the total finish time?

  • All four processors finish at the same moment because the pieces are equal in size

  • The processor with the harder piece finishes last and determines when the whole job ends

  • The total time drops in exact proportion to the number of processors

Reveal answer
Answer:

The processor with the harder piece finishes last and determines when the whole job ends.

Equal size describes the input to each subproblem, not how long each subproblem takes to run. The longest subproblem sets the finish time, so the other processors finish early and then wait.

Why Equal Size Is Not Equal Time

The source identifies two separate reasons why equal-sized pieces can finish at different times. Keeping them apart makes the problem easier to reason about. Equal size is a property of the input to each subproblem. It says nothing about how long each subproblem will run once a processor starts on it.

Where the Finish Time Really Comes From

The speedup from adding processors depends on how evenly the work finishes, not only on how many processors exist. The longest subproblem sets the finish time. Shortening the other pieces does not help once the longest one is still running, because the job is not complete until every piece is complete.

Processor 1finishes at 2 time unitsProcessor 2finishes at 3 time unitsProcessor 3finishes at 5 time unitsProcessor 4finishes at 9 time units,job ends
Each processor receives a piece of the same size, yet the finish times differ. Which processor finishes last, and when does the whole job end?

The timeline above uses illustrative numbers. Processor 4 holds the piece with the most work, or runs on the slowest or most heavily loaded resource. Its finish time of 9 units is the job's finish time, even though the other three processors completed their pieces much earlier. The idle time of those three processors is the cost of an unbalanced split.

Load Balancing by Handing Out Subtasks

The standard response to uneven work is not to find a perfect split, which is usually impossible to predict. Instead, the problem is divided into many more subproblems than there are processors. Each processor handles several subtasks. When a processor finishes one, it is assigned another, and this continues until every subtask has been given out.

The effect is that processors which finish quickly take on more work, and slow or busy processors take on less. Each processor effectively works at its own pace. The diagram below shows the flow of work rather than a fixed assignment. A processor that is slow on one subtask simply returns to the pool later, so it does not hold up the subtasks that remain.

Split into manysubtasksmore subtasks thanprocessorsAssign next subtaskto a free processorProcessor finishesits current subtaskSubtasks remaining?All subtasks doneprocessor worksyesno
When a processor finishes its subtask, what happens next? It takes the next waiting subtask if any remain, which keeps it busy.
Worked example

Tracing a Pool of Subtasks Across Three Processors

A job is divided into 8 subtasks with the following work amounts, in time units: A=1, B=4, C=2, D=1, E=3, F=2, G=1, H=2. Three processors take subtasks from a shared pool in order whenever they become free. Trace the assignments and find when the last processor finishes.

  1. 1
    Start

    All three processors are free at time 0. They take the first three subtasks in the pool: P1 takes A (1 unit), P2 takes B (4 units), P3 takes C (2 units).

  2. 2
    Time 1

    P1 finishes A and becomes free. It takes the next subtask, D (1 unit), which will finish at time 2.

  3. 3
    Time 2

    P3 finishes C and P1 finishes D, both at time 2. P3 takes E (3 units), finishing at time 5. P1 takes F (2 units), finishing at time 4.

  4. 4
    Time 4

    P1 finishes F and becomes free. It takes G (1 unit), finishing at time 5.

  5. 5
    Time 5

    P1 finishes G and P3 finishes E, both at time 5. P1 takes H (2 units), finishing at time 7. P2 is still working on B, which finishes at time 4 and was already complete before this point, so P2 has been free since time 4 with no subtask left to take.

  6. 6
    End

    P1 finishes H at time 7. No subtasks remain, so the last finish time is 7. The total work is 16 units, so the ideal time with three processors would be about 5.3 units. The gap comes from the lumpy sizes of the final pieces.

Result

The job finishes at time 7. No processor was handed a fixed share in advance; each took the next subtask as it became free.

Independent Subtasks Versus Dependent Ones

Load balancing is easiest when subtasks are independent. Independent subtasks can run in any order and at the same time, so a free processor can take any waiting subtask without checking anything. The source's image program is a very easy case because each of its subproblems is completely independent. Any number of them can run at once, and no subtask must wait for another.

Choosing How Big Each Subtask Should Be

Making subproblems small is what makes the many-subtasks approach work, but there is a limit. The source's guidance is that subproblems should be small but not too small. Subproblems should be small enough that processors stay busy, but not so small that the overhead of creating and assigning them becomes significant.

Subtask size involves a trade-off between two costs. If subtasks are too large, there are too few of them for the pool to smooth out differences, so some processors finish early and sit idle while a large subtask runs elsewhere. If subtasks are too small, the creation and assignment of each one adds a computational overhead, and when pieces are very small that overhead can add significantly to the total work.

Idle time near theendlarge pieces finish lateIdle timelow, work spreads evenlyIdle timelow, pieces fill gapsScheduling overheadlow, few assignmentsScheduling overheadreasonableScheduling overheadhigh, many assignments
How does changing the size of each subtask affect idle time on one side and scheduling overhead on the other?

Row-by-Row Splitting in the Image Example

The source's image program shows how the trade-off is resolved in practice. A pixel-by-pixel split would produce subtasks that are probably too small, because each one would carry very little work relative to the cost of creating and assigning it. Instead, each subtask computes one row of pixels. Since the image has several hundred rows, there are many subtasks, and each one is still substantial.

Worked example

Choosing a Granularity for an Image Split

An image has 400 rows and 400 pixels per row. Compare three ways of dividing the work among 8 processors: one subtask per pixel, one subtask per row, and one subtask for each quarter of the image.

  1. 1
    Pixel granularity

    There are 160,000 subtasks. Each one is tiny, so the cost of creating and assigning 160,000 pieces is likely to add significantly to the total work. This is the too-small side of the trade-off.

  2. 2
    Row granularity

    There are 400 subtasks, each computing one row of 400 pixels. Each processor handles about 50 rows, the pool has plenty of pieces to smooth out differences, and each piece is still substantial. This matches the source's description of fairly good load balancing with a reasonable amount of overhead.

  3. 3
    Quarter granularity

    There are only 4 subtasks for 8 processors. Four processors would stay idle for the whole job, and the remaining four would each run a large piece. This is the too-large side of the trade-off.

Result

One row per subtask gives enough pieces for balancing while keeping each piece large enough that overhead stays modest.

Mistakes Beginners Make

  • Common mistake

    Assuming equal-sized pieces will finish at the same time

    What it looks like

    Four equal-sized pieces are given to four processors, and one piece contains much harder computation.

    Why it fails

    Equal size describes the input, not the run time. The harder piece keeps its processor busy long after the others stop.

    Do this instead

    Expect variation in work content and processor speed, and design the split so that a slow piece cannot dominate the finish time.

  • Common mistake

    Dividing the job into exactly one subtask per processor

    What it looks like

    Eight processors each receive exactly one of eight pieces.

    Why it fails

    No processor that finishes early has any other work to take, so it sits idle while the longest piece runs.

    Do this instead

    Divide the problem into many more subproblems than there are processors, and let processors take new subtasks as they become free.

  • Common mistake

    Making every subtask as small as possible

    Why it fails

    The overhead of creating and assigning very small subtasks can add significantly to the total work.

  • Common mistake

    Treating dependent subtasks like independent ones

    Why it fails

    When subtasks depend on each other's results, their order matters, so a free processor cannot simply take any waiting subtask.

Practice: Predict the Finish Time

MEDIUM

Two processors are available. The job is split into five subtasks with work amounts 6, 2, 2, 2, and 2 time units, handed out from a shared pool whenever a processor becomes free. Which processor takes which subtask, and what is the finish time of the whole job? Then consider whether splitting the 6-unit subtask into smaller pieces would help, and what it would cost.

Hints
  • Start by giving the first two subtasks to the two free processors, then find which one becomes free first.
  • The job ends when the last subtask finishes on any processor, not when the average processor finishes.
  • Splitting the large subtask shortens the longest piece but adds creation and assignment overhead for each new piece.

Key Takeaways

  • Equal-sized subproblems do not guarantee equal completion times, because the work inside each piece and the speed or availability of each processor can differ.
  • The longest subproblem sets the finish time, so the speedup from adding processors depends on how evenly the work finishes.
  • Load balancing divides a problem into many more subproblems than there are processors and assigns each new subtask to whichever processor becomes free next.
  • Subtasks should be small enough to keep processors busy but not so small that the overhead of creating and assigning them becomes significant.
  • Independent subtasks can run in any order at the same time, which makes load balancing much simpler than when subtasks depend on each other's results.