0Pricing
Learn Rust Coding · Aula

Canais mpsc

Envie entre threads

Canais mpsc é uma aula grátis de Learn Rust Coding no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Learn Rust Coding, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Learn Rust Coding inclui 4 aulas no total.

Partes desta aula ainda não foram traduzidas e aparecem em inglês.

What Is a Channel?

A channel is a one-way pipe for sending values from one thread to another. Rust's standard library provides std::sync::mpsc where mpsc means multiple producer, single consumer.

  • The Sender half pushes values in.
  • The Receiver half pulls values out.

Channels let threads communicate by passing messages instead of sharing memory directly, which avoids many data races.

Creating a Channel

Call mpsc::channel() to get a tuple of (Sender, Receiver). Here we send one value from a spawned thread back to the main thread.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        tx.send(42).unwrap();
    });
    let received = rx.recv().unwrap();
    println!("Got: {}", received);
}

send and recv

tx.send(value) returns a Result: it fails only if the receiver has been dropped. rx.recv() blocks until a value arrives, returning Err when all senders are gone.

  • send moves ownership of the value into the channel.
  • recv takes ownership out on the other side.
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        let msg = String::from("hello from thread");
        tx.send(msg).unwrap();
    });
    let text = rx.recv().unwrap();
    println!("{}", text);
}

Ownership Moves Through the Channel

Because send takes the value by value, you cannot use it after sending. This compile-time rule guarantees no thread keeps a stale reference to data now owned by another thread.

Below, trying to print msg after send would be a compile error, so we only use it once.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        let data = vec![1, 2, 3];
        tx.send(data).unwrap();
        // data is moved; cannot use it here
    });
    let v = rx.recv().unwrap();
    println!("Sum: {}", v.iter().sum::<i32>());
}

Iterating Over a Receiver

A Receiver implements IntoIterator. Looping over it yields each value until the channel closes (all senders dropped). This is the idiomatic way to consume a stream of messages.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        for i in 1..=3 {
            tx.send(i).unwrap();
        }
    });
    for received in rx {
        println!("Received: {}", received);
    }
}

Multiple Producers with clone

The mp in mpsc means you can have many senders. Clone the Sender and give a copy to each thread. The receiver collects everything until every clone is dropped.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let tx2 = tx.clone();
    thread::spawn(move || { tx.send("from A").unwrap(); });
    thread::spawn(move || { tx2.send("from B").unwrap(); });
    for msg in rx {
        println!("{}", msg);
    }
}

Channel Closing Semantics

The receiver loop ends automatically when all senders are dropped. If even one Sender stays alive, for msg in rx blocks forever waiting for more. Always drop or scope senders correctly to let the loop finish.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        for i in 0..3 {
            tx.send(i * 10).unwrap();
        }
        // tx dropped here, closing the channel
    });
    handle.join().unwrap();
    let total: i32 = rx.iter().sum();
    println!("Total: {}", total);
}

try_recv for Non-Blocking Reads

recv blocks, but try_recv returns immediately with a Result. It gives Ok(value) if a message is ready, or Err if the channel is empty or disconnected. Useful in event loops that must keep doing other work.

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        thread::sleep(Duration::from_millis(50));
        tx.send("ready").unwrap();
    });
    loop {
        match rx.try_recv() {
            Ok(msg) => { println!("{}", msg); break; }
            Err(_) => println!("waiting..."),
        }
        thread::sleep(Duration::from_millis(20));
    }
}

Sending Custom Types

Any type that is Send can travel through a channel, including your own structs and enums. Enums are great for modeling distinct message kinds in a worker protocol.

use std::sync::mpsc;
use std::thread;

enum Job {
    Print(String),
    Add(i32, i32),
}

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        tx.send(Job::Print(String::from("hi"))).unwrap();
        tx.send(Job::Add(2, 3)).unwrap();
    });
    for job in rx {
        match job {
            Job::Print(s) => println!("print: {}", s),
            Job::Add(a, b) => println!("add: {}", a + b),
        }
    }
}

sync_channel and Backpressure

mpsc::sync_channel(n) creates a bounded channel with buffer size n. When the buffer is full, send blocks until space frees up. This gives you backpressure, preventing a fast producer from overwhelming a slow consumer.

  • sync_channel(0) is a rendezvous channel: send and recv must meet.
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::sync_channel(2);
    thread::spawn(move || {
        for i in 1..=4 {
            tx.send(i).unwrap();
            println!("sent {}", i);
        }
    });
    for v in rx {
        println!("got {}", v);
    }
}

A Simple Worker Pattern

Channels shine for the producer/consumer pattern: one thread produces work items, another consumes and processes them. Here the main thread produces numbers and a worker squares each one and reports back over a second channel.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (job_tx, job_rx) = mpsc::channel();
    let (res_tx, res_rx) = mpsc::channel();
    thread::spawn(move || {
        for n in job_rx {
            res_tx.send(n * n).unwrap();
        }
    });
    for n in 1..=4 {
        job_tx.send(n).unwrap();
    }
    drop(job_tx);
    for r in res_rx {
        println!("square: {}", r);
    }
}

Quick Check

Test your understanding of mpsc channels.

Recap

You learned the core of mpsc channels:

  • mpsc::channel() returns a (Sender, Receiver) pair.
  • send moves a value in; recv blocks to take it out.
  • Iterating a receiver consumes messages until all senders drop.
  • Clone the Sender for multiple producers.
  • try_recv is non-blocking; sync_channel(n) adds bounded backpressure.

Channels let threads share data safely by passing ownership rather than sharing memory.

Perguntas Frequentes

A aula “Canais mpsc” é grátis?

Sim — o texto completo de “Canais mpsc” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Learn Rust Coding, atualize para CoddyKit PRO. O curso de Learn Rust Coding inclui 4 aulas no total.

O que vou aprender em “Canais mpsc”?

Envie entre threads Você pratica Learn Rust Coding com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Learn Rust Coding?

Nenhuma experiência prévia é necessária. Learn Rust Coding no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Canais mpsc”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Learn Rust Coding?

Sim. Cada aula de Learn Rust Coding inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Canais mpsc
  2. Compartilhamento de estado com Arc/Mutex
  3. Threads com escopo
  4. Canais Crossbeam
← Voltar para Learn Rust Coding