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.
sendmoves ownership of the value into the channel.recvtakes 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.sendmoves a value in;recvblocks to take it out.- Iterating a receiver consumes messages until all senders drop.
- Clone the
Senderfor multiple producers. try_recvis 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.