1 điểm bởi GN⁺ 2023-10-08 | 1 bình luận | Chia sẻ qua WhatsApp
  • Bài viết này thảo luận về tranh cãi trong cộng đồng Rust xoay quanh việc sử dụng bộ thực thi đa luồng, tức các runtime async thực hiện work-stealing để phân phối công việc một cách cân bằng.
  • Một số người dùng Rust ủng hộ một kiến trúc thay thế gọi là "thread-per-core", hứa hẹn hiệu năng tốt hơn và dễ triển khai hơn.
  • Thuật ngữ "thread-per-core" dễ gây hiểu nhầm. Mọi bộ thực thi đa luồng đều là thread-per-core, tạo một OS thread cho mỗi lõi và lập lịch công việc trên các luồng đó.
  • Thread-per-core kết hợp ba ý tưởng: xử lý đồng thời trong không gian người dùng, biến I/O thành bất đồng bộ để tránh chặn luồng, và phân vùng dữ liệu giữa các lõi CPU để loại bỏ chi phí đồng bộ hóa cũng như việc di chuyển dữ liệu giữa các bộ nhớ đệm CPU.
  • Tranh cãi này chủ yếu xoay quanh điểm thứ ba, còn async Rust có thể đáp ứng hai yêu cầu đầu tiên.
  • Trong kiến trúc thread-per-core, có thể thực hiện hai tối ưu hóa: đánh cắp công việc giữa các luồng và chia sẻ ít trạng thái nhất có thể.
  • Work-stealing cải thiện tail latency bằng cách giúp mọi luồng luôn có việc để làm, nhưng khó triển khai và có thể gây ra chi phí đồng bộ hóa cùng cache miss.
  • Share-nothing cải thiện tail latency bằng cách giữ dữ liệu trong bộ nhớ đệm nhanh hơn gắn với một lõi CPU duy nhất, nhưng có thể khó triển khai với các ứng dụng phức tạp cần thay đổi trạng thái trên nhiều phân vùng.
  • Bài viết cho rằng trong các hệ thống dùng trạng thái chia sẻ, work-stealing có thể cải thiện mức sử dụng CPU khi chịu tải.

1 bình luận

 
GN⁺ 2023-10-08
Ý kiến trên Hacker News
  • Trọng tâm của cuộc tranh luận không phải là các executor đánh cắp công việc theo mô hình một luồng trên mỗi lõi, mà là liệu async/await trong Rust có phải là một abstraction tốt hay không.
  • Mô hình một luồng trên mỗi lõi được phát minh để giải quyết khả năng mở rộng và hiệu quả của tính toán trên các máy chủ nhiều lõi phổ biến, và đã được chứng minh là đặc biệt xuất sắc với các tác vụ I/O-bound thông lượng cao.
  • Kiến trúc một luồng trên mỗi lõi sẽ tiếp tục tồn tại nhờ khả năng mở rộng và hiệu quả của nó, nhưng phần lớn kỹ sư phần mềm có trực giác khá hạn chế về việc một thiết kế một luồng trên mỗi lõi hiện đại và đúng chuẩn trông như thế nào.
  • Một số ứng dụng phù hợp hơn với hệ thống đơn luồng, và Rust cho phép sự linh hoạt này.
  • Có những chỉ trích đối với lập trình async của Rust, bao gồm việc yêu cầu Send + Sync + 'static, và một số người cảm thấy điều này khá nặng nề.
  • Ràng buộc Send là yêu cầu cho phép di chuyển tác vụ giữa các luồng của executor, và đây có vẻ là một khuyết điểm của hệ thống async trong Rust.
  • Không có một cách tiếp cận chung nào đạt hiệu năng tốt nhất cho mọi chương trình, và việc dùng async bị xem là tối ưu hóa quá sớm đối với nhiều chương trình Rust.
  • Vì chuyển ngữ cảnh ở mức kernel có chi phí cao nên người ta ưu tiên thiết kế một luồng trên mỗi lõi, nhưng việc lập lịch chuyển ngữ cảnh ở không gian người dùng cũng có thể gây vấn đề.
  • Đánh cắp công việc là cách để xử lý độ trễ đuôi, nhưng nó dẫn đến cache miss và thêm các ràng buộc cho lập trình viên như Send, Sync'static.