0Pricing
Learn Rust Coding · 강의

결과 결합하고 수집하기

스레드를 기다리고 출력을 모아 보세요.

결과 결합하고 수집하기은(는) CoddyKit의 무료 Learn Rust Coding 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Learn Rust Coding 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Learn Rust Coding 강의에는 총 4개의 강의가 포함되어 있습니다.

스레드를 결합하는 이유

스레드를 생성하면 작업이 시작되지만, 보통 그 결과나 적어도 작업이 완료되었다는 확인이 필요합니다. 결합은 작업이 끝날 때까지 기다리는 방법입니다.

이 레슨에서는 핸들을 수집하고 결합한 뒤, 스레드가 생성한 값을 최종 결과로 모읍니다.

join은 Result를 반환합니다

join은 Result를 반환합니다. 성공하면 클로저의 반환값을 담고, 스레드에서 패닉이 발생하면 Err를 담습니다.

unwrap을 호출하면 값을 직접 얻을 수 있지만, 스레드가 실패하면 패닉이 전파됩니다.

use std::thread;

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

먼저 핸들 수집하기

스레드를 병렬로 실행하려면 하나를 결합하기 전에 모두 생성하십시오. 생성하는 동안 각 핸들을 벡터에 넣습니다.

스레드 생성 반복문 안에서 바로 결합하면 각 스레드가 다음 스레드가 시작되기 전에 끝나므로 병렬성이 사라집니다.

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());
    }
}

Vec에 결과 수집하기

모든 핸들을 결합하고 반환된 값을 결과 벡터에 넣을 수 있습니다.

여기서는 생성 순서와 결합 순서가 모두 0부터 3까지이므로 결과 벡터가 예측 가능한 순서로 만들어집니다.

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);
}

병렬 결과 합산하기

결과를 수집한 뒤에는 결과를 하나로 줄일 수 있습니다. 여기서는 각 스레드가 부분 값을 계산하고, main이 이를 합산합니다.

이러한 map 후 reduce 형태는 일반적인 병렬 패턴입니다.

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);
}

작업을 청크로 나누기

데이터가 많다면 데이터를 청크로 나누고 각 청크를 자체 스레드에 전달하십시오. 각 스레드는 부분 합계를 반환합니다.

각 청크를 소유된 Vec으로 복제하면 스레드가 해당 슬라이스를 안전하게 소유할 수 있습니다.

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);
}

스레드 패닉 처리하기

작업 스레드에서 패닉이 발생할 수 있다면 unwrap을 무조건 사용하지 마십시오. join에서 반환된 Result를 매칭하여 오류 경로를 처리하십시오.

이렇게 하면 작업 스레드 하나가 실패해도 main 스레드가 계속 실행됩니다.

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"),
    }
}

공유 Vec에 수집하기

값을 반환하는 대신 스레드가 공유된 Arc<Mutex<Vec>>에 값을 넣을 수도 있습니다. 이 경우 순서는 결정적이지 않습니다.

모든 스레드를 결합한 뒤 벡터를 한 번 잠그고 수집된 모든 결과를 읽습니다.

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());
}

스코프가 지정된 스레드

thread::scope를 사용하면 move나 Arc 없이도 스레드가 지역 데이터를 빌릴 수 있습니다. 스코프는 반환하기 전에 모든 스레드가 완료되도록 보장합니다.

덕분에 스택 데이터에 대한 병렬 읽기를 간결하고 안전하게 작성할 수 있습니다.

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()));
    });
}

스코프에서 결과 반환하기

스코프가 지정된 스레드도 핸들을 통해 값을 반환합니다. 결과를 모으려면 스코프 안에서 스레드를 결합합니다.

스코프가 완료될 때까지 실행을 멈추므로 빌린 데이터가 전체 작업 동안 유효하게 유지됩니다.

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);
}

결합을 잊지 마십시오

결합하지 않고 JoinHandle을 삭제하면 스레드가 분리됩니다. 스레드는 계속 실행되지만 결과를 얻거나 완료될 때까지 기다릴 방법을 잃게 됩니다.

분리된 스레드가 끝나기 전에 프로세스가 종료될 수도 있습니다. 결과나 완료 여부가 필요하다면 결합하십시오.

빠른 확인

스레드 결합과 결과 수집에 대한 이해도를 확인해 보십시오.

복습

join이 스레드의 값이나 패닉을 담은 Result를 반환한다는 점을 배웠습니다. 먼저 모든 스레드를 생성한 다음 결합해야 병렬성을 유지할 수 있습니다.

결과를 Vec에 수집하고 하나로 줄이거나, 공유된 Arc<Mutex<Vec>>에 넣을 수 있습니다. 스코프가 지정된 스레드는 지역 데이터를 안전하게 빌리며, 핸들을 삭제하면 스레드가 분리됩니다.

이제 Rust의 스레드와 공유 상태를 다루는 핵심 도구를 갖추었습니다.

자주 묻는 질문

“결과 결합하고 수집하기” 강의는 무료인가요?

네 — “결과 결합하고 수집하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Learn Rust Coding 강의 전체를 잠금 해제할 수 있습니다. Learn Rust Coding 강의에는 총 4개의 강의가 포함되어 있습니다.

“결과 결합하고 수집하기”에서 뭘 배우나요?

스레드를 기다리고 출력을 모아 보세요. 브라우저에서 직접 실행하는 실습 코드로 Learn Rust Coding을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Learn Rust Coding을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Learn Rust Coding은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“결과 결합하고 수집하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Learn Rust Coding 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Learn Rust Coding 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 스레드 생성하기
  2. 스레드로 데이터 이동하기
  3. Arc와 Mutex로 공유하기
  4. 결과 결합하고 수집하기
← Learn Rust Coding(으)로 돌아가기