Canais Crossbeam
Canais avançados
Canais Crossbeam é uma aula grátis de Learn Rust Coding no CoddyKit. Esta é a aula 4 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.
Além de std mpsc
O canal padrão mpsc tem um único consumidor: apenas um receptor. O crate crossbeam-channel oferece canais com vários produtores e vários consumidores (mpmc), com mais recursos e, muitas vezes, melhor desempenho.
Destaques:
Receivers clonáveis, não apenas remetentes.- Uma macro
select!poderosa para esperar em vários canais. - Canais limitados, ilimitados e especiais, como os de marcação de tempo.
Adicionando a dependência
Crossbeam é um crate externo, então adicione-o a Cargo.toml:
[dependencies]crossbeam-channel = "0.5"
Depois, importe suas funções. Como isso exige Cargo e um crate externo, os trechos aqui ilustram a API em vez de serem executados de forma independente.
// Cargo.toml
// [dependencies]
// crossbeam-channel = "0.5"
use crossbeam_channel::unbounded;
fn main() {
let (s, r) = unbounded();
s.send("hello").unwrap();
println!("{}", r.recv().unwrap());
}unbounded e bounded
Crossbeam oferece dois construtores principais:
unbounded()cresce conforme necessário;sendnunca bloqueia.bounded(cap)tem um buffer fixo;sendbloqueia quando ele está cheio, fornecendo contrapressão.
Um canal bounded(0) é um canal de encontro, no qual send e recv transferem os dados diretamente.
use crossbeam_channel::bounded;
use std::thread;
fn main() {
let (s, r) = bounded(2);
thread::spawn(move || {
for i in 1..=3 {
s.send(i).unwrap();
}
});
while let Ok(v) = r.recv() {
println!("got {}", v);
}
}Vários consumidores
A principal vantagem é que você pode clonar o Receiver. Várias threads de trabalho podem retirar mensagens do mesmo canal, e cada mensagem vai exatamente para uma delas. Essa é a base de um conjunto de threads com distribuição de trabalho.
use crossbeam_channel::unbounded;
use std::thread;
fn main() {
let (s, r) = unbounded();
let mut workers = vec![];
for id in 0..3 {
let rx = r.clone();
workers.push(thread::spawn(move || {
while let Ok(job) = rx.recv() {
println!("worker {} got job {}", id, job);
}
}));
}
for job in 0..6 { s.send(job).unwrap(); }
drop(s);
for w in workers { w.join().unwrap(); }
}A macro select!
select! permite que uma thread espere por operações em vários canais e aja sobre aquela que estiver pronta primeiro. É como um match sobre eventos de canais, ideal para combinar entradas de várias fontes.
use crossbeam_channel::{unbounded, select};
use std::thread;
fn main() {
let (s1, r1) = unbounded();
let (s2, r2) = unbounded();
thread::spawn(move || { s1.send("from one").unwrap(); });
thread::spawn(move || { s2.send("from two").unwrap(); });
for _ in 0..2 {
select! {
recv(r1) -> msg => println!("r1: {}", msg.unwrap()),
recv(r2) -> msg => println!("r2: {}", msg.unwrap()),
}
}
}Timeouts com select!
select! oferece um ramo default e um ramo de temporizador recv(after(duration)), para que você possa desistir de esperar após um timeout em vez de bloquear indefinidamente. Isso é essencial para sistemas responsivos.
use crossbeam_channel::{unbounded, select, after};
use std::time::Duration;
fn main() {
let (_s, r) = unbounded::<i32>();
select! {
recv(r) -> msg => println!("received {:?}", msg),
recv(after(Duration::from_millis(100))) -> _ => {
println!("timed out waiting for a message");
}
}
}try_send e try_recv
Assim como a biblioteca padrão, o crossbeam fornece variantes não bloqueantes. try_send falha imediatamente se um canal limitado estiver cheio; try_recv falha imediatamente se nenhuma mensagem estiver pronta. Ambos retornam um erro descritivo que você pode analisar.
use crossbeam_channel::{bounded, TrySendError};
fn main() {
let (s, _r) = bounded(1);
s.send(1).unwrap();
match s.try_send(2) {
Ok(()) => println!("sent"),
Err(TrySendError::Full(v)) => println!("full, kept {}", v),
Err(TrySendError::Disconnected(v)) => println!("closed, kept {}", v),
}
}tick e trabalho periódico
A função tick(duration) retorna um receptor que entrega uma mensagem em intervalos fixos. Combine-a com select! para executar tarefas periódicas junto com outros canais, como um sinal de atividade ou um loop de consulta.
use crossbeam_channel::{tick, select};
use std::time::Duration;
fn main() {
let ticker = tick(Duration::from_millis(50));
let mut count = 0;
while count < 3 {
select! {
recv(ticker) -> _ => {
count += 1;
println!("tick {}", count);
}
}
}
}Um pipeline de etapas
Crossbeam é excelente para criar pipelines: a primeira etapa produz, a segunda transforma e a terceira consome. Cada etapa é executada em sua própria thread, conectada por canais, e receptores clonados permitem escalar qualquer etapa para vários trabalhadores.
use crossbeam_channel::unbounded;
use std::thread;
fn main() {
let (in_s, in_r) = unbounded();
let (out_s, out_r) = unbounded();
thread::spawn(move || {
for n in in_r { out_s.send(n * n).unwrap(); }
});
for n in 1..=4 { in_s.send(n).unwrap(); }
drop(in_s);
for sq in out_r { println!("square: {}", sq); }
}Quando Crossbeam supera std
Use crossbeam-channel quando precisar de:
- Vários consumidores compartilhando uma fila (conjuntos de trabalhadores).
select!em vários canais com timeouts.- Temporizadores periódicos por meio de
tickintegrados à seleção.
Para um canal simples de um produtor e um consumidor, o mpsc padrão é suficiente e não exige dependência.
Os canais são fechados ao descartar
Assim como no std, os canais do crossbeam são fechados quando todos os remetentes (no lado do receptor) ou todos os receptores (no lado do remetente) são descartados. A iteração sobre um receptor termina depois que o último remetente é descartado. Sempre use drop ou limite o escopo dos remetentes para que os loops de trabalho possam sair de forma limpa.
use crossbeam_channel::unbounded;
use std::thread;
fn main() {
let (s, r) = unbounded();
let h = thread::spawn(move || {
let total: i32 = r.iter().sum();
println!("total: {}", total);
});
for i in 1..=5 { s.send(i).unwrap(); }
drop(s); // closes channel so the loop ends
h.join().unwrap();
}Verificação rápida
Teste sua compreensão sobre canais do crossbeam.
Recapitulação
Você explorou canais do crossbeam:
- Eles são mpmc: tanto os remetentes quanto os receptores podem ser clonados.
unbounded()ebounded(n)controlam o armazenamento em buffer e a contrapressão.select!espera em vários canais, com timeouts por meio deaftere dotickperiódico.try_send/try_recvsão não bloqueantes.- Use crossbeam para conjuntos de trabalhadores e pipelines complexos; use std mpsc para canais simples.
Perguntas Frequentes
A aula “Canais Crossbeam” é grátis?
Sim — o texto completo de “Canais Crossbeam” é 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 Crossbeam”?
Canais avançados 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 4 de 4.
Quanto tempo leva a aula “Canais Crossbeam”?
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.