Unindo threads e reunindo resultados
Aguarde as threads e reúna a saída.
Unindo threads e reunindo resultados é 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.
Por que fazer join das threads?
Criar uma thread inicia o trabalho, mas normalmente você precisa do resultado ou, pelo menos, da confirmação de que ele terminou. Fazer join é a forma de esperar.
Nesta lição, você collect handles, fará join deles e reunirá os valores produzidos em uma resposta final.
join retorna um resultado
join retorna um Result. Em caso de sucesso, ele contém o valor retornado pela closure; se uma thread entrar em panic, ele conterá um Err.
Chamar unwrap fornece o valor diretamente, mas propaga um panic se a thread falhar.
use std::thread;
fn main() {
let h = thread::spawn(|| 7 * 6);
let value: i32 = h.join().unwrap();
println!("answer = {}", value);
}Coletando os handles primeiro
Para executar threads em paralelo, crie todas elas com spawn antes de fazer qualquer join. Adicione cada identificador a um vetor à medida que avança.
Se fizer join dentro do laço de spawn, cada thread terminará antes que a próxima comece, e a concorrência será perdida.
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());
}
}Coletando resultados em um Vec
Você pode fazer join de cada identificador e adicionar os valores retornados a um vetor de resultados.
A ordem de criação e a ordem de união percorrem de zero a três neste caso, portanto o vetor de resultados termina em uma ordem previsível.
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);
}Somando resultados paralelos
Depois de coletar os resultados, você pode reduzi-los. Aqui, cada thread calcula um valor parcial, e main soma esses valores.
Esse formato de mapear e depois reduzir é um padrão paralelo comum.
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);
}Dividindo o trabalho em partes
Para dados maiores, divida-os em partes e entregue cada parte à sua própria thread. Cada thread retorna uma soma parcial.
Clonar cada parte em um Vec com propriedade própria permite que a thread seja proprietária da sua fatia com segurança.
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);
}Lidando com o pânico de uma thread
Se uma thread de trabalho puder entrar em pânico, não use unwrap cegamente. Faça uma correspondência sobre o Result retornado por join para lidar com o caminho de erro.
Assim, a thread principal continua ativa mesmo quando uma thread de trabalho falha.
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"),
}
}Coletando em um Vec compartilhado
Em vez de retornar valores, as threads podem adicioná-los a um Arc<Mutex<Vec>> compartilhado. A ordem será, então, não determinística.
Depois de fazer join de todas as threads, bloqueie o vetor uma única vez para ler cada resultado coletado.
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());
}Threads com escopo
thread::scope permite que as threads tomem dados locais emprestados sem move ou Arc. O escopo garante que todas as threads terminem antes de retornar.
Isso torna as leituras paralelas de dados da pilha práticas e seguras.
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()));
});
}Retornando resultados do escopo
As threads com escopo também retornam valores por meio dos seus identificadores. Você faz join delas dentro do escopo para reunir os resultados.
Como o escopo bloqueia até a conclusão, os dados emprestados permanecem válidos durante todo o processo.
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);
}Não se esqueça de fazer join
Se você descartar um JoinHandle sem fazer join, a thread será desanexada. Ela continuará executando, mas você perderá o resultado e qualquer forma de esperar por ela.
O processo também poderá terminar antes que uma thread desanexada conclua. Faça join quando precisar do resultado ou da conclusão.
Verificação rápida
Teste seu entendimento sobre fazer join e coletar resultados.
Recapitulação
Você aprendeu que join retorna um Result contendo o valor ou o pânico de uma thread. Crie todas as threads primeiro e só depois faça join para manter a concorrência.
Você pode coletar resultados em um Vec, reduzi-los ou adicioná-los a um Arc<Mutex<Vec>> compartilhado. Threads com escopo tomam dados locais emprestados com segurança, e descartar um identificador desanexa a thread.
Agora você tem as ferramentas fundamentais para trabalhar com threads e estado compartilhado em Rust.
Perguntas Frequentes
A aula “Unindo threads e reunindo resultados” é grátis?
Sim — o texto completo de “Unindo threads e reunindo resultados” é 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 “Unindo threads e reunindo resultados”?
Aguarde as threads e reúna a saída. 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 “Unindo threads e reunindo resultados”?
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.
Todas as aulas deste curso
- Criando threads
- Movendo dados para threads
- Compartilhando com Arc e Mutex
- Unindo threads e reunindo resultados