mpsc-kanaler
Send mellem tråde
mpsc-kanaler er en gratis Lær at programmere i Rust-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Lær at programmere i Rust, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Lær at programmere i Rust-kurset indeholder 4 lektioner i alt.
Hvad er en kanal?
En kanal er et envejsrør, der sender værdier fra én tråd til en anden. Rusts standardbibliotek leverer std::sync::mpsc, hvor mpsc betyder flere producenter, én forbruger.
- Den ene halvdel, Sender, sender værdier ind.
- Den anden halvdel, Receiver, henter værdier ud.
Kanaler lader tråde kommunikere ved at sende beskeder i stedet for at dele hukommelse direkte, hvilket undgår mange datakapløb.
Oprettelse af en kanal
Kald mpsc::channel() for at få en tupel med (Sender, Receiver). Her sender vi én værdi fra en startet tråd tilbage til hovedtråden.
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 og recv
tx.send(value) returnerer en Result: den mislykkes kun, hvis receiveren er blevet droppet. rx.recv() blokerer, indtil en værdi ankommer, og returnerer Err, når alle sendere er væk.
sendflytter ejerskabet af værdien ind i kanalen.recvovertager ejerskabet på den anden 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);
}Ejerskab flyttes gennem kanalen
Fordi send tager værdien som værdi, kan du ikke bruge den efter afsendelsen. Denne regel ved kompilering sikrer, at ingen tråd beholder en forældet reference til data, som nu ejes af en anden tråd.
Nedenfor ville et forsøg på at udskrive msg efter send være en kompileringsfejl, så vi bruger den kun én gang.
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>());
}Iteration over en Receiver
En Receiver implementerer IntoIterator. En løkke over den giver hver værdi, indtil kanalen lukkes (alle sendere er droppet). Dette er den idiomatiske måde at forbruge en strøm af beskeder på.
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);
}
}Flere producenter med clone
mp i mpsc betyder, at du kan have mange sendere. Klon Sender, og giv en kopi til hver tråd. Receiveren samler alt, indtil alle kloner er droppet.
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);
}
}Semantik for lukning af kanaler
Receiver-løkken afsluttes automatisk, når alle sendere er droppet. Hvis blot én Sender forbliver aktiv, blokerer for msg in rx for evigt, mens den venter på flere. Drop altid senderne, eller begræns deres scope korrekt, så løkken kan afsluttes.
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 til ikke-blokerende læsning
recv blokerer, men try_recv returnerer straks en Result. Den giver Ok(value), hvis en besked er klar, eller Err, hvis kanalen er tom eller afbrudt. Det er nyttigt i event loops, der skal fortsætte med andet arbejde.
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));
}
}Afsendelse af brugerdefinerede typer
Alle typer, der er Send, kan sendes gennem en kanal, herunder dine egne structs og enums. Enums er velegnede til at modellere forskellige beskedtyper i en worker-protokol.
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 og backpressure
mpsc::sync_channel(n) opretter en afgrænset kanal med bufferstørrelsen n. Når bufferen er fuld, blokerer send, indtil der bliver plads. Det giver backpressure og forhindrer en hurtig producent i at overbelaste en langsom forbruger.
sync_channel(0)er en rendezvous-kanal: send og recv skal mødes.
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);
}
}Et simpelt workermønster
Kanaler er ideelle til producent-/forbrugermønsteret: én tråd producerer arbejdsenheder, mens en anden forbruger og behandler dem. Her producerer hovedtråden tal, og en arbejdertråd kvadrerer hvert tal og rapporterer resultatet tilbage via en anden kanal.
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);
}
}Hurtigt tjek
Test din forståelse af mpsc-kanaler.
Opsummering
Du har lært det grundlæggende om mpsc-kanaler:
mpsc::channel()returnerer et par bestående af(Sender, Receiver).sendflytter en værdi ind, mensrecvblokerer for at hente den ud.- Iteration over en modtager forbruger meddelelser, indtil alle sendere droppes.
- Klon
Senderfor at få flere producenter. try_recvblokerer ikke, menssync_channel(n)tilføjer begrænset modtryk.
Kanaler lader tråde dele data sikkert ved at overføre ejerskab i stedet for at dele hukommelse.
Lær Rust med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 39
- Lektioner
- 144
Ofte stillede spørgsmål
Er lektionen “mpsc-kanaler” gratis?
Ja — alle 3 lektioner i læringssporet Lær at programmere i Rust, inklusive “mpsc-kanaler”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Lær at programmere i Rust-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “mpsc-kanaler”?
Send mellem tråde Du øver dig i Lær at programmere i Rust med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Lær at programmere i Rust?
Der kræves ingen tidligere erfaring. Lær at programmere i Rust på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.
Hvor lang tid tager lektionen “mpsc-kanaler”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Lær at programmere i Rust-lektion?
Ja. Alle Lær at programmere i Rust-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.