[0]
Rust의 비동기 프로그래밍을 위한 async/await 키워드와 Future trait에 대해 알아본다.
[1]
Rust는 async/await, 그리고 이와 관련한 Future trait을 통해 비동기를 지원한다. 다음과 같이 간단히 사용할 수 있다. Future는 trait으로 다음과 같은 간단히 선언되어 있다.
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
trait 자체는 Output type과 poll메소드로 매우 간단하다. poll에서는 Context라는 구조체를 변수로 받는데, 이에 대해서는 나중에 설명하도록 하겠다. async 키워드를 이용해 다음과 같이 Future trait object를 만들 수 있다.
async fn worker(){
println!("this is worker!");
}
async{
println("this is anonymous async!")
}
함수 선언에 async 키워드를 붙이거나, async 블록을 이용해서도 Future object를 만들 수 있다. 이 코드들은 일반적인 방식으로는 실행할 수 없다. 예를 들어 worker()로 호출하더라도 아무 의미 없는 구문일 뿐이다. 이를 실행하기 위해서는 await을 사용해야 한다.
async fn worker(){
println!("this is worker!");
}
fn main() {
worker().await;
}
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> src\main.rs:10:5
|
5 | fn main() {
| ---- this is not `async`
...
10 | worker().await;
| ^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
error: aborting due to previous error
하지만 Future object에 무작정 await를 하면 위와 같이 await는 async 블록 내에서만 사용할 수 있다는 에러가 발생한다. 그럼 main을 async로 바꿔보자.
error[E0752]: `main` function is not allowed to be `async`
--> src\main.rs:5:1
|
5 | async fn main() {
| ^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
error: aborting due to 2 previous errors
main은 async로 선언할 수 없다는 에러를 뱉는다. 그럼 임의로 async 블록을 만들고 그 안에서 await해보자.
async fn worker(){
println!("this is worker!");
}
fn main() {
async{
worker().await;
};
}
위와 같은 코드는 컴파일 가능하지만, "this is worker"가 출력되지는 않는다. main 내의 async블록이 await되지 않았기 때문이다. 정리해보자면 await를 하기 위해선 async 내부여야 하고, main은 async로 선언될 수 없다. 따라서 main이 아닌 최상위의 async 블록이 필요한데, 그 최상위의 async를 실행시킬 수가 없다! 이를 해결하기 위해서는 별도의 executor가 필요하다.
[2]
여기에서는 가장 널리 사용되는 tokio를 사용하겠다.
use tokio::prelude::*;
async fn worker(){
println!("this is worker!");
}
#[tokio::main]
async fn main() {
worker().await;
tokio::task::spawn(worker());
}
Cargo.toml에 tokio를 full feature로 포함시키면 위의 코드를 실행시킬 수 있다. worker().await또는 직접 task::spawn()을 사용하여 async 블록을 실행할 수 있다. 하지만 tokio는 꽤나 복잡하기 때문에 async가 어떻게 돌아가는지 알기는 다소 어렵다. 다음 포스팅에서 executor를 직접 구현하면서 async의 동작에 대해 알아보자.
[참고]
https://rust-lang.github.io/async-book/
'Computer Science > Rust' 카테고리의 다른 글
Unsafe Rust (0) | 2020.09.27 |
---|---|
Rust의 trait object (0) | 2020.08.02 |
Rust의 Copy trait와 Clone trait (2) | 2020.06.30 |
Rust의 스마트 포인터 (0) | 2020.05.20 |
Rust의 lifetime parameter (0) | 2020.05.05 |