Course contentsShow
← Rust
Lesson 1114 of 1,91010. Concurrency PrimitivesFree lesson

Pipeline Parallelism Patterns

You will structure multi-stage data processing chains to maximize throughput in streaming applications.

In this lesson, you will learn how to structure multi-stage data processing chains to maximize throughput in streaming applications using pipeline parallelism.

The Assembly Line Analogy

Pipeline parallelism is a concurrency pattern that mimics a physical assembly line. Instead of a single worker performing every task on a data item, you divide the process into distinct stages. Each stage runs in its own dedicated thread, and items flow through the pipeline as they are completed. By partitioning the work, you ensure that every processor core can work on a different stage of a different data item simultaneously, vastly increasing the total throughput of your system.

Implementing a Stage

To build a pipeline, you connect stages using channels. Each stage typically follows a simple loop: receive an input from the upstream channel, perform the stage-specific transformation, and send the result to the downstream channel.

Consider a simple two-stage transformation pipeline:

use std::sync::mpsc::{channel, Sender};
use std::thread;

fn spawn_stage_one(next: Sender<i32>) {
    thread::spawn(move || {
        for i in 0..10 {
            // Stage 1: e.g., "Parse"
            next.send(i * 2).unwrap();
        }
    });
}

fn spawn_stage_two(receiver: std::sync::mpsc::Receiver<i32>) {
    thread::spawn(move || {
        for val in receiver {
            // Stage 2: e.g., "Transform"
            println!("Processed: {}", val + 1);
        }
    });
}

Balancing the Flow

The secret to effective pipelining is balancing stage latency. If "Stage 1" is much faster than "Stage 2," the internal buffers in your channels will fill up, causing "Stage 1" to block. Conversely, if "Stage 2" is faster, it will sit idle waiting for input.

In Rust, you handle this by choosing appropriate channel buffering strategies. Synchronous (bounded) channels are often preferred in pipelines because they provide backpressure; if a downstream stage falls behind, the upstream stage is naturally slowed down, preventing unbounded memory growth. When designing your pipeline, always measure the latency of each stage to ensure they are evenly distributed, allowing data to flow through the "assembly line" without bottlenecks.

Key Takeaway: Pipeline parallelism maximizes throughput by dividing tasks into independent stages connected by channels, allowing different items to be processed in parallel across separate execution units.