퓨처와 작업 다루기
`Future` 트레이트와 비동기 런타임 환경에서 작업이 예약되고 관리되는 방식을 이해합니다.
퓨처와 작업 다루기은(는) CoddyKit의 무료 Learn Rust Coding 강의입니다. 이것은 3개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Learn Rust Coding 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Learn Rust Coding 강의에는 총 3개의 강의가 포함되어 있습니다.
Rust Future란 무엇인가요?
비동기 Rust에서 Future는 언젠가 완료될 수 있는 비동기 계산을 나타내는 트레이트입니다. 아직 준비되지 않은 값을 위한 약속이라고 생각하시면 됩니다.
- 비동기 Rust를 구성하는 핵심 요소입니다.
- Rust의
async fn은 실제로Future트레이트를 구현하는 익명 타입을 반환합니다. - 값은 즉시 계산되지 않고, 실행기가
Future를 "폴링"할 때 계산됩니다.
Future가 진행하는 방식
Future는 스스로 실행되지 않습니다. Tokio 런타임과 같은 실행기가 반복해서 이를 "폴링"하여 진행되었는지 또는 완료되었는지 확인합니다.
- 폴링되면
Future는Poll::Pending(아직 완료되지 않음) 또는Poll::Ready(T)(완료됨, 결과는 다음과 같음) 중 하나를 반환합니다. Pending이면 실행기는 관련 이벤트가 발생한 뒤(예: 입출력 완료) 다시 폴링해야 한다는 것을 알 수 있습니다.- 이 폴링 메커니즘 덕분에 하나의 스레드에서 많은 비동기 작업을 동시에 실행할 수 있습니다.
여러분의 async 코드는 Future입니다
async fn을 작성하면 Rust는 이를 Future 트레이트를 구현하는 상태 머신으로 변환합니다. 실제 계산은 반환된 Future가 폴링될 때만 시작됩니다.
간단한 async 함수를 살펴보겠습니다. 이 함수는 실행기에 의해 기다려질 때까지 실행되지 않습니다.
async fn say_hello() -> String {
"Hello from a Future!".to_string()
}
#[tokio::main]
async fn main() {
let future = say_hello(); // This doesn't run the function yet!
println!("Future created, but not awaited.");
// To run it, an executor needs to poll it, often via .await
// let result = future.await;
// println!("{}", result);
}Future가 작업이 되는 과정
Future가 비동기 계산의 정의라면, 작업은 실행기가 해당 Future를 완료까지 진행시키는 활성 인스턴스입니다.
- Tokio와 같은 실행기에
Future를 실행하라고 요청하면 실행기는 이를 작업으로 감쌉니다. - 그런 다음 실행기는 작업이 진행할 준비가 될 때마다 폴링하며 작업을 관리합니다.
- 작업은 비동기 런타임이 예약하고 동시에 실행하는 작업 단위입니다.
동시 실행을 위한 작업 생성
Future를 다른 코드와 동시에 실행하려면 Tokio 런타임에 이를 "생성"해야 합니다. 그러면 런타임이 관리할 새 작업이 만들어집니다.
tokio::spawn 함수는 Future를 받아 JoinHandle을 반환합니다. 이 핸들을 사용하면 작업의 완료를 기다리고 결과를 얻을 수 있습니다.
async fn perform_task(id: u8) -> String {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
format!("Task {} finished!", id)
}
#[tokio::main]
async fn main() {
println!("Main started.");
let handle = tokio::spawn(async {
perform_task(1).await
});
println!("Task 1 spawned.");
// We will await 'handle' in the next scene to get the result.
// let result = handle.await.unwrap();
// println!("{}", result);
}작업에서 결과 가져오기
tokio::spawn이 반환하는 JoinHandle 자체도 Future입니다. 이 핸들을 .await하면 생성된 작업이 완료될 때까지 기다린 후 반환값을 가져올 수 있습니다.
생성된 작업이 패닉을 일으키면 해당 JoinHandle을 기다린 결과로 오류가 반환됩니다.
async fn perform_task(id: u8) -> String {
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
format!("Task {} finished!", id)
}
#[tokio::main]
async fn main() {
println!("Main started.");
let handle = tokio::spawn(async {
perform_task(1).await
});
println!("Task 1 spawned.");
let result = handle.await.unwrap(); // Await the handle to get the result
println!("{}", result);
println!("Main finished.");
}여러 동시 작업
여러 작업과 tokio::spawn을 사용해 여러 작업을 동시에 실행할 때 그 강력한 기능이 진정으로 드러납니다. Tokio 런타임은 작업이 실행할 준비가 될 때마다 작업 사이를 효율적으로 전환합니다.
따라서 하나의 스레드에서도 실행을 차단하지 않고 여러 작업을 한꺼번에 진행할 수 있습니다.
async fn long_task(id: u8) -> String {
tokio::time::sleep(tokio::time::Duration::from_millis(100 + id as u64 * 50)).await;
format!("Long task {} done!", id)
}
#[tokio::main]
async fn main() {
println!("Main started.");
let handle1 = tokio::spawn(long_task(1));
let handle2 = tokio::spawn(long_task(2));
println!("Both tasks spawned.");
let result1 = handle1.await.unwrap();
let result2 = handle2.await.unwrap();
println!("{}\n{}", result1, result2);
println!("Main finished.");
}join!으로 모두 기다리기
여러 Future가 동시에 완료되기를 기다려야 할 때 tokio::join!은 유용한 매크로입니다. 주어진 모든 퓨처를 동시에 기다린 다음 그 결과를 튜플로 반환합니다.
각 핸들을 개별적으로 기다리는 것과 비슷하지만, 퓨처의 개수가 정해져 있을 때 더 간결한 경우가 많습니다.
async fn fetch_data(source: &str) -> String {
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
format!("Data from {}", source)
}
#[tokio::main]
async fn main() {
println!("Starting data fetches...");
let (data_a, data_b) = tokio::join!(
fetch_data("Server A"),
fetch_data("Database B")
);
println!("Fetched: {}\nFetched: {}", data_a, data_b);
println!("All fetches complete.");
}작업 오류 처리
비동기 작업도 동기 작업과 마찬가지로 실패할 수 있습니다. Future가 성공 또는 실패를 나타내는 Result 타입을 반환하는 것은 흔한 방식입니다.
JoinHandle을 기다릴 때는 작업 자체가 패닉을 일으킬 수 있으므로 결과가 또 다른 Result 안에 감싸져 있다는 점을 기억하세요. async fn 내부에서 Result를 반환한다면 handle.await?를, 또는 handle.await.unwrap() / .expect()를 자주 보게 됩니다.
async fn might_fail(should_fail: bool) -> Result<String, &'static str> {
tokio::time::sleep(tokio::time::Duration::from_millis(30)).await;
if should_fail {
Err("Oops, something went wrong!")
} else {
Ok("Operation successful!".to_string())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let handle_ok = tokio::spawn(might_fail(false));
let handle_err = tokio::spawn(might_fail(true));
let result_ok = handle_ok.await??; // Await handle, then await inner Result
println!("{}", result_ok);
match handle_err.await? { // Await handle, then handle inner Result
Ok(val) => println!("{}", val),
Err(e) => eprintln!("Error: {}", e),
}
Ok(())
}Future와 작업 이해하기
계산으로서의 Future와 실행 인스턴스로서의 작업을 배웠습니다. tokio::spawn과 JoinHandle에 대한 설명 중 옳은 것은 무엇일까요?
복습: Future와 작업
훌륭합니다! 이제 Rust 비동기 생태계의 Future와 작업에 관한 핵심 개념을 이해하셨습니다.
Future는 언젠가 값을 생성할 비동기 계산을 나타내는 트레이트입니다.async fn은Future트레이트를 구현하는 타입으로 컴파일됩니다.- 작업은 실행기(Tokio 등)가 적극적으로 관리하고 폴링하는
Future의 인스턴스입니다. tokio::spawn은 새 작업을 만들며JoinHandle을 반환합니다.- 생성된 작업의 결과를 얻으려면
JoinHandle을.await합니다.
이 구성 요소들은 효율적이고 비차단 방식의 Rust 애플리케이션을 작성하는 데 필수적입니다!
자주 묻는 질문
“퓨처와 작업 다루기” 강의는 무료인가요?
네 — “퓨처와 작업 다루기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Learn Rust Coding 강의 전체를 잠금 해제할 수 있습니다. Learn Rust Coding 강의에는 총 3개의 강의가 포함되어 있습니다.
“퓨처와 작업 다루기”에서 뭘 배우나요?
`Future` 트레이트와 비동기 런타임 환경에서 작업이 예약되고 관리되는 방식을 이해합니다. 브라우저에서 직접 실행하는 실습 코드로 Learn Rust Coding을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Learn Rust Coding을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Learn Rust Coding은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 3개 중 3번째 강의입니다.
“퓨처와 작업 다루기” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Learn Rust Coding 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Learn Rust Coding 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- Async/Await 입문
- Tokio로 비동기 애플리케이션 만들기
- 퓨처와 작업 다루기