- Trong cộng đồng Rust, thường xuất hiện câu hỏi: thread có thể làm được mọi thứ mà async/await làm được và còn đơn giản hơn, vậy tại sao lại chọn async/await?
- Rust là ngôn ngữ cấp thấp, không che giấu độ phức tạp của coroutine. Đây là khái niệm đối lập với các ngôn ngữ như Go, nơi mọi thứ về cơ bản trở thành bất đồng bộ mà lập trình viên gần như không cần phải nghĩ đến bất đồng bộ.
- Lập trình viên giỏi luôn cố tránh sự phức tạp, vậy tại sao lại cần
async/await?
Tìm hiểu bối cảnh
- Rust là ngôn ngữ cấp thấp. Mã thường mang tính tuyến tính: một tác vụ kết thúc rồi tác vụ khác mới chạy.
- Trong những trường hợp cần chạy đồng thời nhiều tác vụ như máy chủ web, mã tuyến tính sẽ gây ra vấn đề.
- Web thời kỳ đầu đã cố giải quyết vấn đề này bằng cách đưa threading vào.
- Có thể dùng thread để xử lý nhiều client cùng lúc, nhưng các lập trình viên muốn đưa tính đồng thời từ không gian của OS sang không gian người dùng.
Vấn đề timeout
- Một trong những ưu điểm lớn nhất của Rust là tính khả hợp (composability).
async/await cho phép áp dụng tính khả hợp này cho các hàm bị ràng buộc bởi I/O.
- Ví dụ, khi muốn thêm timeout vào một hàm xử lý client, có thể triển khai bằng hai combinator.
Thread theo chủ đề
- Trong ví dụ dùng thread, việc triển khai timeout không hề dễ dàng.
TcpStream có các hàm set_read_timeout và set_write_timeout, nhưng cách dùng chúng khá hạn chế.
- Bài viết đưa ra cách lập trình timeout bằng combinator của Rust, nhưng cách này chỉ giới hạn ở
TcpStream và cần thêm các system call.
Các trường hợp async thành công
- Hệ sinh thái HTTP đã chấp nhận
async/await làm cơ chế runtime chủ đạo.
tower là ví dụ cho thấy sức mạnh của async/await, với các tính năng như timeout, giới hạn tốc độ và cân bằng tải.
macroquad là game engine Rust chạy engine bằng async/await.
Cải thiện hình ảnh của async
- Lợi ích của
async chưa được biết đến rộng rãi nên một số người có thể hiểu sai.
- Cộng đồng Rust có xu hướng đánh giá quá cao lợi thế hiệu năng của
async Rust và xem nhẹ những lợi ích thực sự có ý nghĩa của nó.
async/await nên được xem là một mô hình lập trình mạnh mẽ có thể diễn đạt ngắn gọn những mẫu mà trong Rust đồng bộ phải cần đến hàng chục thread và channel mới biểu đạt được.
Ý kiến của GN⁺
async/await làm tăng độ phức tạp của mã khi xử lý tính đồng thời, nhưng đồng thời mang lại khả năng xử lý hiệu quả rất nhiều client cùng lúc.
- Bài viết nhấn mạnh rằng
async/await không chỉ đơn thuần có lợi thế về hiệu năng mà còn có thế mạnh ở mô hình lập trình.
async/await trong Rust mang lại tính khả hợp cho nhiều tác vụ I/O khác nhau, đặc biệt hữu ích trong các lĩnh vực như dịch vụ mạng hoặc máy chủ web.
- Nhìn từ góc độ phê bình, độ phức tạp của
async/await có thể trở thành rào cản gia nhập với lập trình viên mới, và cần có nỗ lực giáo dục để vượt qua điều đó.
- Các dự án khác cung cấp chức năng tương tự gồm phần triển khai
async/await của Node.js và thư viện asyncio của Python; chúng cũng cung cấp một mô hình tương tự.
- Khi đưa
async/await vào sử dụng, cần cân nhắc độ phức tạp và khả năng bảo trì của mã; tuy nhiên, nếu phải xử lý đồng thời rất nhiều client thì mô hình này mang lại lợi thế lớn.
1 bình luận
Ý kiến trên Hacker News
Async/await và luồng đơn
Mutextiêu chuẩn và channelcrossbeam-channelđều không công bằng.Async/await so với thread
Vấn đề của bài viết
Những điểm chưa được đề cập
Điểm quan trọng về hủy bỏ
Chiến dịch như marketing cho async/await
Async/await so với fiber
Lợi ích chính của async/await trong Rust
Những hiểu lầm về async/await
Lý do chọn async/await thay vì thread