Ce face thread::scope
thread::scope(|s| { ... }) creează o zonă în care pornești fire cu s.spawn(|| ...). Înainte ca scope să se termine, toate firele pornite în ea sunt așteptate automat. Datorită acestei garanții, firele pot împrumuta variabile locale (&date, chiar &mut), fără Arc și fără move.
s.spawn returnează un ScopedJoinHandle, pe care poți face join() ca să iei rezultatul. Dacă un fir intră în panică și nu i-ai făcut join, panica se propagă din scope. Valoarea returnată de closure-ul lui scope este returnată de scope.
Parametri
| Parametru | Descriere |
|---|---|
f |
Closure-ul care primește s (obiectul Scope) și pornește firele. |
Ce returnează
Valoarea returnată de closure.
Exemple
Exemplul 1: Fire care împrumută un vector local
Cele două jumătăți ale vectorului sunt adunate în paralel. Nu am avut nevoie de Arc sau de clone.
use std::thread;
fn main() {
let vanzari = vec![120, 340, 90, 410, 250, 180];
let (stanga, dreapta) = vanzari.split_at(vanzari.len() / 2);
let (a, b) = thread::scope(|s| {
let h1 = s.spawn(|| stanga.iter().sum::<i32>());
let h2 = s.spawn(|| dreapta.iter().sum::<i32>());
(h1.join().unwrap(), h2.join().unwrap())
});
println!("prima jumătate: {a} lei, a doua: {b} lei, total: {} lei", a + b);
println!("vectorul este tot aici: {vanzari:?}");
}
Rezultat
prima jumătate: 550 lei, a doua: 840 lei, total: 1390 lei
vectorul este tot aici: [120, 340, 90, 410, 250, 180]
Exemplul 2: Modificare în paralel cu &mut
chunks_mut împarte vectorul în bucăți separate; fiecare fir primește &mut la bucata lui.
use std::thread;
fn main() {
let mut preturi = vec![10.0, 20.0, 30.0, 40.0, 50.0, 60.0];
thread::scope(|s| {
for bucata in preturi.chunks_mut(2) {
s.spawn(move || {
for p in bucata.iter_mut() {
*p *= 1.19;
}
});
}
});
let rotunjite: Vec<String> = preturi.iter().map(|p| format!("{p:.2}")).collect();
println!("cu TVA: {}", rotunjite.join(", "));
}
Rezultat
cu TVA: 11.90, 23.80, 35.70, 47.60, 59.50, 71.40
Greșeli frecvente
- Încerci să returnezi din
scopeo referință spre ceva creat în interiorul lui: datele trăiesc doar cât zona. - Folosești în fire același
&mutde două ori: compilatorul refuză; împarte datele cusplit_at_mutsauchunks_mut.
Comenzi înrudite
thread::spawn: Pornește un fir de execuție nou care rulează funcția dată; join() așteaptă terminarea lui și îi dă rezultatul.Mutex: Protejează o valoare folosită din mai multe fire: lock() așteaptă până când firul curent este singurul cu acces.AtomicUsize: Număr întreg care poate fi citit și modificat din mai multe fire fără Mutex, cu operații atomice.Arc: Varianta lui Rc care poate fi împărțită între fire: contorul de proprietari este actualizat atomic.