Rust Async: Future Và Async/Await Trong Rust

Rust Async: Future Và Async/Await Trong Rust

Rust là ngôn ngữ lập trình hệ thống an toàn bộ nhớ, và mô hình async của nó là một trong những mạnh mẽ nhất hiện nay. Bài viết này giải thích Future, async, và await — nền tảng của lập trình bất đồng bộ trong Rust.

Output Clippy trong dự án Rust hiển thị warningsMáy tính để bàn lập trình với logo Rust

Future Là Gì?

Một Future trong Rust là một giá trị đại diện cho kết quả của một phép tính bất đồng bộ có thể chưa hoàn thành. Nó giống như một “promise” — bạn có thể kiểm tra xem nó đã sẵn sàng chưa và lấy kết quả khi xong. Future được định nghĩa trong thư viện std với trait:

trait Future {
    type Output;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

Khi được tạo, một Future ở trạng thái Pending. Khi runtime gọi poll, nó có thể trả về Ready(value) hoặc tiếp tục Pending. Điều này cho phép Rust xử lý hàng nghìn tác vụ đồng thời mà không cần tạo thread cho từng tác vụ.

async/await Cú Pháp

Hàm async bao bọc logic thành Future. Từ khóa await tạm dừng execution cho đến khi Future hoàn thành:

async fn fetch_data() -> Result<String, Error> {
    let response = reqwest::get("https://api.example.com").await?;
    let body = response.text().await?;
    Ok(body)
}

Hàm fetch_data trả về một Future. Khi gọi .await, runtime sẽ “thức dậy” (wake) task khi dữ liệu sẵn sàng. Cú pháp này khiến async code đọc giống synchronous code, dễ hiểu và bảo trì.

Runtime: Tokio Và async-std

Future đơn lẻ không tự chạy. Cần một runtime để điều phối:

  • Tokio: Runtime phổ biến nhất, hỗ trợ multi-thread, I/O-driven, kênh truyền tin (mpsc, broadcast), thời gian (timeout, interval)
  • async-std: Runtime nhẹ hơn, tương thích với std API, phù hợp cho ứng dụng đơn giản
  • smol: Mini runtime cho nhúng hoặc môi trường hạn chế
  • actix-web: Web framework dựa trên Tokio, hiệu suất cực cao

Khởi tạo runtime Tokio:

#[tokio::main]
async fn main() {
    let data = fetch_data().await.unwrap();
    println!("{}", data);
}

Runtime chịu trách nhiệm: quản lý task scheduling, I/O polling, timer, và wake mechanism.

Waker và Context

Khi Future không sẵn sàng, nó trả về Pending và lưu Waker trong Context. Runtime gọi wake() khi tài nguyên sẵn sàng. Cơ chế này tránh busy-waiting, giúp Rust async tiết kiệm CPU hơn cả thread-based models.

Waker hoạt động như một “gọi dậy” — khi I/O hoàn thành, nó gửi tín hiệu cho runtime để tiếp tục xử lý task tương ứng. Điều này tạo nên hiệu quả của model event-driven.

So Sánh Với Thread

Tiêu chí Thread Async
Chi phí khởi tạo ~1MB stack/thread ~KB/async task
Số lượng đồng thời Vài nghìn Hàng trăm nghìn
Context switch Kernel (chậm) User-space (nhanh)
Debugging Dễ Phức tạp hơn
Error handling Bất đồng bộ phức tạp Kết hợp với ? operator

Ví dụ thực tế: máy chủ web dùng async có thể xử lý 100,000 kết nối đồng thời trên một máy 8GB RAM. Cùng máy với thread-based server chỉ xử lý được vài nghìn kết nối trước khi hết bộ nhớ.

Error Handling Trong Async

? operator hoạt động như thường kỳ trong async fn. Kết hợp với ResultOption, Rust giữ nguyên kiểm tra lỗi chặt chẽ ngay cả trong async code. Thư viện thiserror tạo error type tùy chỉnh, anyhow cho error handling linh hoạt.

async fn handle_request() -> Result<Response, MyError> {
    let data = fetch_data().await?;
    let processed = process(data).await?;
    Ok(Response::new(processed))
}

Lưu Ý Khi Dùng Async

  • Blocking trong async: Dùng tokio::task::spawn_blocking cho tác vụ blocking như file I/O hoặc gọi hệ thống
  • Send + Sync: Future phải là Send để chạy trên multi-thread runtime. !Send types cần spawn trên current thread
  • Lazy vs Eager: Future chỉ thực thi khi được poll, không phải khi tạo. Điều này cho phép composition không tốn cost
  • Testing: Dùng tokio::test attribute cho async test, #[tokio::test(flavor = "multi_thread")] cho concurrency test
  • Backpressure: Sử dụng kênh có bounds (mpsc::channel(32)) để tránh queue vô hạn

Ví Dụ Thực Tế: Web Server

Xây dựng web server đơn giản với Tokio và Hyper:

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Server, Request, Response};

async fn handle(_req: Request) -> Result<Response, hyper::Error> {
    Ok(Response::new(Body::from("Hello, Rust async!")))
}

#[tokio::main]
async fn main() {
    let addr = ([127, 0, 0, 1], 3000).into();
    let make_svc = make_service_fn(|_conn| async {
        Ok::(service_fn(handle))
    });
    let server = Server::bind(&addr).serve(make_svc);
    server.await.unwrap();
}

Server này xử lý hàng nghìn kết nối đồng thời trên một thread duy nhất nhờ async I/O. Đây là sức mạnh mà Rust async mang lại.

Kết Luận

Rust async kết hợp zero-cost abstraction với an toàn bộ nhớ — Future là core, async/await là sugar, runtime như Tokio là nhạc cụ. Hệ sinh thái đang phát triển nhanh chóng với hàng ngàn crate hỗ trợ async trên crates.io. Kết hợp với trait system và type inference, Rust tạo ra code async vừa an toàn vừa hiệu suất cao.

Bắt đầu từ crate tokio, khám phá reqwest cho HTTP client, serde cho serialization, và sqlx cho database async. Xem Rust Async Book để học sâu hơn và Tokio docs cho tài liệu API.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Flask vs Django: Hướng Dẫn Chọn Framework Python Phù Hợp

Việc chọn framework Python phù hợp là quyết định quan trọng ảnh hưởng trực tiếp đến tốc độ phát triển, khả năng mở rộng và chi phí bảo trì của…

Xem thêm

Go 1.24: Các Tính Năng Mới Cho Lập Trình Viên

Go 1.24: Các Tính Năng Mới Cho Lập Trình Viên Go 1.24 ra mắt tháng 8/2025 mang đến những cải tiến đáng kể về hiệu suất, trải nghiệm phát triển,…

Xem thêm

TypeScript 5.6: Type Inference Mạnh Hơn Và Performance Tốt Hơn

TypeScript 5.6: Type Inference Mạnh Hơn Và Performance Tốt Hơn TypeScript 5.6: Type Inference Mạnh Hơn Và Performance Tốt Hơn TypeScript tiếp tục phát triển mạnh mẽ với phiên bản…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất