task parallelism
Think of a small restaurant kitchen during a dinner rush. One cook works the grill, another the fryer, a third plates and garnishes, and a fourth washes dishes. They are not all doing the same thing to different food — each does a different job, and the meal flows through them. Task parallelism is this division of labor inside a program: you split the work into distinct tasks that do different things, and run those different tasks at the same time on different threads or cores.
Concretely, task parallelism (the task-decomposition view) divides the work by function rather than by data. Imagine a program that, for each incoming video frame, must decode it, run face detection on it, and update the on-screen statistics. You can put decode on thread 0, face detection on thread 1, and statistics on thread 2; they perform genuinely different operations, often passing partial results down a pipeline. Where data parallelism replicates one operation across many data slices, task parallelism spreads several different operations across the cores. Tasks may need to coordinate, because one task's output is often another task's input.
The limits are different in flavor from data parallelism. Task parallelism is bounded by how many genuinely independent tasks the problem actually contains — if there are only three distinct stages, three cores is the ceiling, and a fourth core sits idle. It also tends to suffer load imbalance: if the face-detection task is far slower than the others, the whole pipeline runs at its pace and the faster threads wait. In practice large programs blend both styles — task parallelism to separate the stages, then data parallelism inside a heavy stage to use the leftover cores.
A music app might run three different tasks at once: one thread reads the audio file from disk, a second decodes the compressed data into sound samples, and a third sends those samples to the speakers. Three threads, three distinct jobs, chained as a pipeline — that is task parallelism.
Different operations on different cores — split the work, not the data.
Task parallelism can only use as many cores as the problem has genuinely independent stages, so it scales poorly when there are few distinct tasks. It also stalls at the speed of its slowest stage.