Cuộc tranh luận về Async/Await: Tại sao cách tiếp cận đồng thời của Go có thể tốt hơn

BigGo Editorial Team
Cuộc tranh luận về Async/Await: Tại sao cách tiếp cận đồng thời của Go có thể tốt hơn

Cộng đồng lập trình đang tham gia vào một cuộc tranh luận sôi nổi về async/await, một tính năng đã trở nên phổ biến trong các ngôn ngữ lập trình hiện đại. Mặc dù ban đầu được ca ngợi như một giải pháp cho địa ngục callback, tính năng này đã gây ra tranh cãi giữa các lập trình viên khi cho rằng nó tạo ra nhiều vấn đề hơn là giải quyết chúng.

Vấn đề về Function Coloring

Một trong những chỉ trích lớn nhất về async/await là vấn đề được gọi là function coloring. Khi một hàm sử dụng await, nó phải được đánh dấu là async, và yêu cầu này lan truyền qua toàn bộ call stack. Sự lây nhiễm của các đánh dấu async này đã trở thành một điểm gây khó chịu lớn cho các lập trình viên, dẫn đến sự phức tạp và khó chịu trong mã nguồn.

Các Cách Tiếp Cận Thay Thế

Cách tiếp cận đồng thời của Go đã thu hút sự chú ý như một giải pháp thay thế tiềm năng. Thay vì async/await, Go sử dụng goroutines và channels, triển khai theo mô hình được gọi là Communicating Sequential Processes (CSP). Cách tiếp cận này cho phép lập trình viên viết mã có vẻ đồng bộ trong khi runtime xử lý độ phức tạp của việc thực thi đồng thời.

CSP đơn giản hơn. Đơn giản hơn nghĩa là dễ làm đúng hơn. Trước đây tôi thường viết nhiều máy chủ bất đồng bộ bằng C cho đến vài thập kỷ trước. Tôi thấy nó dễ dàng. Hầu hết mọi người thì không. Ngày nay chúng ta có những cách tốt hơn để làm việc này.

Các phương pháp chính về xử lý đồng thời:

  • Async/Await : Coroutines không stack với các đánh dấu async rõ ràng
  • Phương pháp của Go : Coroutines có stack với xử lý đồng thời ngầm định
  • CSP : Giao tiếp giữa các Tiến trình Tuần tự
  • Virtual Threads : Phương pháp của JVM về luồng nhẹ

Lập Luận về Stackful Coroutines

Nhiều lập trình viên cho rằng stackful coroutines, như được triển khai trong Go, cung cấp khả năng trừu tượng hóa tốt hơn so với loại stackless được sử dụng trong hầu hết các triển khai async/await. Sự khác biệt chính nằm ở cách runtime xử lý ngữ cảnh thực thi. Cách tiếp cận của Go cho phép lập trình viên viết mã đơn giản hơn mà không cần đánh dấu rõ ràng các ranh giới async, trong khi vẫn duy trì được hiệu quả thực thi đồng thời.

Thách Thức trong Lập Trình UI

Một điểm ủng hộ đáng kể cho async/await đến từ lập trình UI. Trong các ứng dụng GUI, việc chặn luồng chính dẫn đến giao diện không phản hồi. Async/await cung cấp một cách rõ ràng để xử lý các hoạt động nền trong khi vẫn giữ UI phản hồi nhanh. Điều này làm cho nó đặc biệt có giá trị trong phát triển frontend và ứng dụng desktop.

Vấn Đề về Hiệu Năng

Những phát triển gần đây, như virtual threads của Java, đã thách thức các lập luận về hiệu năng thường được sử dụng để biện minh cho async/await. Một số lập trình viên cho rằng độ phức tạp do async/await mang lại không được biện minh bởi lợi ích về hiệu năng của nó, đặc biệt là trong các ứng dụng kinh doanh thông thường, nơi việc chuyển đổi ngữ cảnh hiếm khi là nút thắt cổ chai.

Kết luận

Mặc dù async/await đã trở thành một tính năng tiêu chuẩn trong nhiều ngôn ngữ lập trình hiện đại, cuộc tranh luận về giá trị của nó vẫn tiếp tục. Cuộc thảo luận này làm nổi bật một căng thẳng rộng lớn hơn trong phát triển phần mềm giữa sự trừu tượng hóa và độ phức tạp, và giữa các cách tiếp cận khác nhau để xử lý các hoạt động đồng thời. Khi lĩnh vực này phát triển, chúng ta có thể thấy những mô hình mới xuất hiện cân bằng tốt hơn giữa các mối quan tâm cạnh tranh này.

Nguồn tham khảo: Async Await Is The Worst Thing To Happen To Programming