0Pricing
Learn Rust Coding · 강의

mpsc 채널

스레드 간에 보내기

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

채널이란 무엇인가요?

채널은 한 스레드에서 다른 스레드로 값을 보내는 단방향 파이프입니다. Rust 표준 라이브러리는 std::sync::mpsc를 제공하며, mpsc는 여러 생산자, 하나의 소비자를 의미합니다.

  • Sender 쪽은 값을 넣습니다.
  • Receiver 쪽은 값을 꺼냅니다.

채널을 사용하면 메모리를 직접 공유하는 대신 메시지를 전달하여 스레드가 통신할 수 있으므로 많은 데이터 경쟁을 방지할 수 있습니다.

채널 만들기

mpsc::channel()을 호출하면 (Sender, Receiver) 튜플을 얻습니다. 여기서는 생성한 스레드에서 주 스레드로 값 하나를 보냅니다.

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와 recv

tx.send(value)는 Result를 반환하며, Receiver가 삭제된 경우에만 실패합니다. rx.recv()는 값이 도착할 때까지 차단되고, 모든 Sender가 사라지면 Err를 반환합니다.

  • send는 값의 소유권을 채널로 이동합니다.
  • recv는 반대편에서 소유권을 가져옵니다.
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);
}

채널을 통한 소유권 이동

send는 값을 값으로 받으므로 전송한 뒤에는 해당 값을 사용할 수 없습니다. 이 컴파일 시점 규칙은 다른 스레드가 소유한 데이터에 대해 어떤 스레드도 오래된 참조를 유지하지 않도록 보장합니다.

아래에서 send 후에 msg를 출력하려 하면 컴파일 오류가 발생하므로, 한 번만 사용합니다.

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

Receiver 반복하기

Receiver는 IntoIterator를 구현합니다. 이를 반복하면 채널이 닫힐 때까지 각 값을 얻습니다. 채널이 닫히는 시점은 모든 Sender가 삭제된 때입니다. 메시지 스트림을 소비하는 관용적인 방법입니다.

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

clone을 사용한 여러 생산자

mpsc의 mp는 여러 Sender를 사용할 수 있다는 의미입니다. Sender를 복제하고 각 스레드에 사본을 전달하세요. Receiver는 모든 복제본이 삭제될 때까지 모든 값을 수집합니다.

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

채널 종료 의미

모든 Sender가 삭제되면 Receiver 반복문이 자동으로 끝납니다. Sender 하나라도 살아 있으면 for msg in rx는 더 많은 값을 기다리며 영원히 차단됩니다. 반복문이 끝나도록 Sender를 항상 올바르게 삭제하거나 범위를 지정하세요.

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

recv는 차단하지만 try_recv는 Result를 즉시 반환합니다. 메시지가 준비되어 있으면 Ok(value)를, 채널이 비어 있거나 연결이 끊겼으면 Err를 반환합니다. 다른 작업도 계속해야 하는 이벤트 반복문에서 유용합니다.

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

사용자 정의 형식 보내기

Send인 형식은 무엇이든 채널을 통해 보낼 수 있으며, 사용자 정의 구조체와 열거형도 포함됩니다. 열거형은 작업자 프로토콜에서 서로 다른 메시지 종류를 모델링하는 데 적합합니다.

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과 역압

mpsc::sync_channel(n)은 버퍼 크기가 n인 제한된 채널을 만듭니다. 버퍼가 가득 차면 공간이 생길 때까지 send가 차단됩니다. 이를 통해 역압이 적용되어 빠른 생산자가 느린 소비자를 압도하는 것을 방지합니다.

  • sync_channel(0)은 랑데부 채널입니다. send와 recv가 만나야 합니다.
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);
    }
}

간단한 작업자 패턴

채널은 생산자/소비자 패턴에서 특히 유용합니다. 한 스레드가 작업 항목을 생성하면 다른 스레드가 이를 소비하고 처리합니다. 여기서는 메인 스레드가 숫자를 생성하고, 작업 스레드가 각 숫자를 제곱한 뒤 두 번째 채널을 통해 결과를 돌려줍니다.

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

빠른 확인

mpsc 채널에 대한 이해도를 확인해 보세요.

복습

mpsc 채널의 핵심을 배웠습니다.

  • mpsc::channel()은 (Sender, Receiver) 쌍을 반환합니다.
  • send는 값을 채널 안으로 이동시키고, recv는 값을 꺼내기 위해 대기합니다.
  • 수신자를 반복하면 모든 송신자가 삭제될 때까지 메시지를 소비합니다.
  • 생산자가 여러 개라면 Sender를 복제합니다.
  • try_recv는 차단되지 않으며, sync_channel(n)은 용량 제한에 따른 역압을 추가합니다.

채널을 사용하면 메모리를 공유하는 대신 소유권을 전달하여 스레드 간에 데이터를 안전하게 공유할 수 있습니다.

자주 묻는 질문

“mpsc 채널” 강의는 무료인가요?

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

“mpsc 채널”에서 뭘 배우나요?

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

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

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

“mpsc 채널” 강의는 얼마나 걸리나요?

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

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

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

이 강의의 모든 강의

  1. mpsc 채널
  2. Arc/Mutex로 상태 공유하기
  3. 범위가 지정된 스레드
  4. Crossbeam 채널
← Learn Rust Coding(으)로 돌아가기