Canaux Crossbeam
Canaux avancés
Canaux Crossbeam est une leçon Learn Rust Coding gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Learn Rust Coding, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Learn Rust Coding comprend 4 leçons au total.
Au-delà de std mpsc
Le canal standard mpsc est à consommateur unique : il n’a qu’un seul récepteur. Le paquet crossbeam-channel fournit des canaux à producteurs multiples et consommateurs multiples (mpmc), avec davantage de fonctionnalités et souvent de meilleures performances.
Points essentiels :
- Des
Receiverclonables, et pas seulement des émetteurs. - Une macro
select!puissante pour attendre sur plusieurs canaux. - Des canaux avec ou sans limite, ainsi que des canaux spéciaux comme ceux produisant des battements.
Ajouter la dépendance
Crossbeam est un paquet externe : ajoutez-le donc à Cargo.toml :
[dependencies]crossbeam-channel = "0.5"
Importez ensuite ses fonctions. Comme cela nécessite Cargo et un paquet externe, les extraits présentés ici illustrent l’API au lieu de s’exécuter seuls.
// 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 et bounded
Crossbeam propose deux constructeurs principaux :
unbounded()s’agrandit selon les besoins ;sendne bloque jamais.bounded(cap)possède un tampon de taille fixe ;sendbloque lorsqu’il est plein, ce qui exerce une contre-pression.
Un canal bounded(0) est un canal de rendez-vous dans lequel send et recv se transmettent directement les données.
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);
}
}Plusieurs consommateurs
L’avantage principal est que vous pouvez cloner le Receiver. Plusieurs threads travailleurs peuvent récupérer des messages sur le même canal, et chaque message est remis à exactement l’un d’entre eux. C’est la base d’un groupe de threads avec répartition du travail.
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(); }
}La macro select!
select! permet à un thread d’attendre plusieurs opérations de canal et d’agir sur celle qui est prête la première. C’est comparable à un match portant sur des événements de canal, ce qui est idéal pour combiner des entrées provenant de plusieurs sources.
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()),
}
}
}Délais d’attente avec select!
select! prend en charge une branche default et une branche de temporisation recv(after(duration)), ce qui permet d’abandonner l’attente après un délai plutôt que de bloquer indéfiniment. C’est essentiel pour les systèmes réactifs.
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 et try_recv
Comme la bibliothèque standard, crossbeam fournit des variantes non bloquantes. try_send échoue immédiatement si un canal limité est plein ; try_recv échoue immédiatement si aucun message n’est prêt. Les deux renvoient une erreur descriptive que vous pouvez examiner avec un match.
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 et travail périodique
La fonction tick(duration) renvoie un récepteur qui fournit un message à intervalle fixe. Combinez-la avec select! pour exécuter des tâches périodiques en parallèle d’autres canaux, par exemple une pulsation ou une boucle d’interrogation.
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);
}
}
}
}Un pipeline d’étapes
Crossbeam excelle dans la création de pipelines : la première étape produit, la deuxième transforme et la troisième consomme. Chaque étape s’exécute dans son propre thread, relié par des canaux, et les récepteurs clonés permettent de répartir chaque étape entre plusieurs travailleurs.
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); }
}Quand Crossbeam est meilleur que std
Utilisez crossbeam-channel lorsque vous avez besoin de :
- Plusieurs consommateurs partageant une même file d’attente (groupes de travailleurs).
- D’un
select!sur plusieurs canaux avec des délais d’attente. - De temporisateurs périodiques via
tick, intégrés à la sélection.
Pour un simple canal reliant un producteur unique à un consommateur unique, mpsc standard convient très bien et ne nécessite aucune dépendance.
Les canaux sont fermés par abandon
Comme avec std, les canaux crossbeam se ferment lorsque tous les émetteurs (du côté du récepteur) ou tous les récepteurs (du côté de l’émetteur) sont abandonnés. L’itération sur un récepteur se termine lorsque le dernier émetteur est abandonné. Utilisez toujours drop ou limitez la portée de vos émetteurs afin que les boucles des travailleurs puissent se terminer proprement.
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();
}Vérification rapide
Vérifiez votre compréhension des canaux crossbeam.
Récapitulatif
Vous avez exploré les canaux crossbeam :
- Ils sont mpmc : les émetteurs comme les récepteurs peuvent être clonés.
unbounded()etbounded(n)contrôlent la mise en tampon et la contre-pression.select!attend sur plusieurs canaux, avec des délais viaafteret un fonctionnement périodique viatick.try_send/try_recvsont non bloquants.- Utilisez crossbeam pour les groupes de travailleurs et les pipelines complexes ; utilisez std mpsc pour les canaux simples.
Questions Fréquemment Posées
La leçon « Canaux Crossbeam » est-elle gratuite ?
Oui — le texte complet de « Canaux Crossbeam » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Learn Rust Coding, passe à CoddyKit PRO. Le cours Learn Rust Coding comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Canaux Crossbeam » ?
Canaux avancés Tu pratiques Learn Rust Coding avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Learn Rust Coding ?
Aucune expérience préalable n'est requise. Learn Rust Coding sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Canaux Crossbeam » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Learn Rust Coding ?
Oui. Chaque leçon Learn Rust Coding inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.