Lär dig programmera i Rust · Lektion

Vänta på trådar och samla resultat

Vänta på trådar och samla in resultat.

Lektion 4 av 413 steg

Vänta på trådar och samla resultat är en gratis lektion i Lär dig programmera i Rust på CoddyKit. Detta är lektion 4 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Lär dig programmera i Rust, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Lär dig programmera i Rust innehåller totalt 4 lektioner.

Varför sammanfoga trådar?

Att starta en tråd påbörjar arbetet, men vanligtvis behöver ni resultatet eller åtminstone bevis på att arbetet blev klart. Att sammanfoga tråden är sättet att vänta.

I den här lektionen samlar ni in handtag, sammanfogar trådarna och samlar värdena de producerar till ett slutligt resultat.

join returnerar ett Result

join returnerar ett Result. Vid lyckat resultat innehåller det klosurens returvärde; om en tråd får panik innehåller det ett Err.

Genom att anropa unwrap får ni värdet direkt, men en panik vidarebefordras om tråden misslyckades.

use std::thread;

fn main() {
    let h = thread::spawn(|| 7 * 6);
    let value: i32 = h.join().unwrap();
    println!("answer = {}", value);
}

Samla in handtagen först

Om trådarna ska köras parallellt startar ni alla innan ni sammanfogar någon av dem. Lägg till varje handtag i en vektor efter hand.

Om ni sammanfogar tråden i startloopen slutförs varje tråd innan nästa startar, och ni förlorar parallelliteten.

use std::thread;

fn main() {
    let handles: Vec<_> = (0..4)
        .map(|i| thread::spawn(move || i * i))
        .collect();
    for h in handles {
        println!("{}", h.join().unwrap());
    }
}

Samla resultat i en Vec

Ni kan sammanfoga varje handtag och lägga de returnerade värdena i en resultatvektor.

Både startordningen och sammanfogningsordningen går här från noll till tre, så resultatvektorn får en förutsägbar ordning.

use std::thread;

fn main() {
    let handles: Vec<_> = (1..=4)
        .map(|n| thread::spawn(move || n * 10))
        .collect();
    let results: Vec<i32> = handles
        .into_iter()
        .map(|h| h.join().unwrap())
        .collect();
    println!("{:?}", results);
}

Summera parallella resultat

När ni har samlat in resultaten kan ni reducera dem. Här beräknar varje tråd ett delresultat, och main summerar dem.

Denna map-och-reduce-struktur är ett vanligt parallellt mönster.

use std::thread;

fn main() {
    let handles: Vec<_> = (1..=5)
        .map(|n| thread::spawn(move || n * n))
        .collect();
    let total: i32 = handles
        .into_iter()
        .map(|h| h.join().unwrap())
        .sum();
    println!("total = {}", total);
}

Dela upp arbetet i delar

För större datamängder delar ni upp datan i delar och ger varje del till en egen tråd. Varje tråd returnerar en delsummma.

Genom att klona varje del till en ägd Vec kan tråden äga sitt utsnitt på ett säkert sätt.

use std::thread;

fn main() {
    let data: Vec<i32> = (1..=10).collect();
    let handles: Vec<_> = data
        .chunks(5)
        .map(|c| { let c = c.to_vec(); thread::spawn(move || c.iter().sum::<i32>()) })
        .collect();
    let total: i32 = handles.into_iter().map(|h| h.join().unwrap()).sum();
    println!("{}", total);
}

Hantera panik i en tråd

Om en arbetstråd kan få panik ska ni inte blint använda unwrap. Matcha mot Result från join för att hantera felvägen.

På så sätt fortsätter huvudtråden att köras även när en arbetstråd misslyckas.

use std::thread;

fn main() {
    let h = thread::spawn(|| {
        if true { panic!("failed"); }
        1
    });
    match h.join() {
        Ok(v) => println!("got {}", v),
        Err(_) => println!("thread panicked"),
    }
}

Samla in data i en delad Vec

I stället för att returnera värden kan trådarna lägga till dem i en delad Arc<Mutex<Vec>>. Ordningen blir då icke-deterministisk.

När alla trådar har sammanfogats låser ni vektorn en gång för att läsa alla insamlade resultat.

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let out = Arc::new(Mutex::new(vec![]));
    let mut handles = vec![];
    for i in 0..3 {
        let o = Arc::clone(&out);
        handles.push(thread::spawn(move || o.lock().unwrap().push(i)));
    }
    for h in handles { h.join().unwrap(); }
    println!("{:?}", out.lock().unwrap());
}

Avgränsade trådar

thread::scope låter trådar låna lokala data utan move eller Arc. Omfånget garanterar att alla trådar slutförs innan det returnerar.

Det gör parallella läsningar av data på stacken både smidiga och säkra.

use std::thread;

fn main() {
    let data = vec![1, 2, 3];
    thread::scope(|s| {
        s.spawn(|| println!("sum {}", data.iter().sum::<i32>()));
        s.spawn(|| println!("len {}", data.len()));
    });
}

Returnera resultat från ett omfång

Avgränsade trådar returnerar också värden genom sina handtag. Ni sammanfogar dem inuti omfånget för att samla in resultaten.

Eftersom omfånget blockerar tills allt är klart förblir lånad data giltig under hela tiden.

use std::thread;

fn main() {
    let nums = vec![4, 5, 6];
    let total = thread::scope(|s| {
        let h = s.spawn(|| nums.iter().sum::<i32>());
        h.join().unwrap()
    });
    println!("total = {}", total);
}

Glöm inte att sammanfoga

Om ni släpper ett JoinHandle utan att sammanfoga tråden blir den frikopplad. Den fortsätter att köras, men ni förlorar resultatet och möjligheten att vänta på den.

Processen kan dessutom avslutas innan en frikopplad tråd hinner bli klar. Sammanfoga tråden när ni behöver resultatet eller vill säkerställa att den är klar.

Snabbtest

Testa era kunskaper om att sammanfoga trådar och samla in resultat.

Sammanfattning

Ni har lärt er att join returnerar ett Result som innehåller en tråds värde eller panik. Starta alla trådar först och sammanfoga dem sedan för att behålla parallelliteten.

Ni kan samla resultat i en Vec, reducera dem eller lägga till dem i en delad Arc<Mutex<Vec>>. Avgränsade trådar lånar lokala data på ett säkert sätt, och om ni släpper ett handtag frikopplas tråden.

Nu har ni de centrala verktygen för trådar och delat tillstånd i Rust.

Gratis att börja

Lär dig Rust med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
39
Lektioner
144

Vanliga frågor

Är lektionen ”Vänta på trådar och samla resultat” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Lär dig programmera i Rust, inklusive ”Vänta på trådar och samla resultat”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Lär dig programmera i Rust innehåller totalt 4 lektioner.

Vad lär jag mig i ”Vänta på trådar och samla resultat”?

Vänta på trådar och samla in resultat. Ni övar på Lär dig programmera i Rust med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Lär dig programmera i Rust?

Du behöver inga förkunskaper. Utbildningen i Lär dig programmera i Rust på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Vänta på trådar och samla resultat”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Lär dig programmera i Rust-lektionen?

Ja. Varje Lär dig programmera i Rust-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Skapa trådar
  2. Flytta data till trådar
  3. Dela med Arc och Mutex
  4. Vänta på trådar och samla resultat
← Tillbaka till Lär dig programmera i Rust