Thư viện asyncio của Python , được giới thiệu vào năm 2012 để mang lập trình bất đồng bộ đến với ngôn ngữ này, đang đối mặt với làn sóng chỉ trích ngày càng tăng từ các nhà phát triển cho rằng nó có quá nhiều lỗi thiết kế và vấn đề về khả năng sử dụng. Thư viện này được tạo ra nhằm cung cấp một giải pháp thay thế cho threading truyền thống trong lập trình đồng thời, nhưng các cuộc thảo luận trong cộng đồng cho thấy sự thất vọng rộng rãi với cách triển khai của nó.
Cơ chế hủy bỏ bị hỏng gây ra đau đầu cho các nhà phát triển
Một trong những vấn đề quan trọng nhất với asyncio là hệ thống hủy bỏ của nó. Không giống như threading truyền thống nơi việc hủy bỏ vốn dĩ khó khăn, asyncio được cho là sẽ làm cho điều này dễ dàng hơn. Tuy nhiên, các nhà phát triển báo cáo rằng cơ chế hủy bỏ bị hỏng từ cơ bản. Khi một tác vụ bị hủy, tín hiệu hủy bỏ có thể biến mất một cách bất ngờ, để lại các hoạt động chạy vô thời hạn ngay cả sau khi chúng đã được dừng lại. Điều này tạo ra các tình huống mà ứng dụng bị treo hoặc tiêu thụ tài nguyên không cần thiết, khiến việc xây dựng các ứng dụng mạnh mẽ có thể xử lý các gián đoạn một cách nhẹ nhàng trở nên cực kỳ khó khăn.
Vấn đề quản lý bộ nhớ dẫn đến các lỗi bí ẩn
Một điểm đau đớn lớn khác là thông báo lỗi khét tiếng Task was destroyed but it is pending. Điều này xảy ra vì asyncio không giữ các tham chiếu mạnh đến các tác vụ, có thể dẫn đến việc các tác vụ bị thu gom rác trong khi chúng vẫn đang chạy. Các nhà phát triển thường xuyên gặp phải lỗi khó hiểu này mà không có hướng dẫn rõ ràng về cách khắc phục. Nguyên nhân gốc rễ nằm ở hệ thống tham chiếu yếu của asyncio , được thiết kế để ngăn chặn rò rỉ bộ nhớ nhưng thay vào đó tạo ra hành vi không thể dự đoán và khó gỡ lỗi.
Độ phức tạp của API cấp thấp làm các nhà phát triển thất vọng
Các API socket và mạng cơ bản trong asyncio bị chỉ trích vì quá phức tạp và đầy rẫy những cạm bẫy. Các hoạt động đơn giản vốn nên dễ dàng lại yêu cầu các nhà phát triển phải hiểu các chi tiết phức tạp về vòng lặp sự kiện và file descriptor. Độ phức tạp này khiến các nhà phát triển khó viết mã mạng đáng tin cậy mà không có kiến thức sâu về nội bộ của asyncio .
Các Vấn Đề Chính Của asyncio Được Cộng Đồng Xác Định
Vấn Đề | Mô Tả | Tác Động |
---|---|---|
Hủy Bỏ Bị Lỗi | Tín hiệu hủy bỏ có thể biến mất, khiến các task chạy vô thời hạn | Ứng dụng bị treo hoặc tiêu tốn tài nguyên không cần thiết |
Lỗi Hủy Task | "Task was destroyed but it is pending" do tham chiếu yếu | Thông báo lỗi khó hiểu và hành vi không thể dự đoán |
API Cấp Thấp Phức Tạp | Socket và các API mạng yêu cầu kiến thức sâu về nội bộ hệ thống | Khó viết mã mạng đáng tin cậy |
Vấn Đề Triển Khai Queue | Xử lý kém các mẫu producer-consumer | Race condition và ứng dụng bị treo |
Triển khai Queue thêm những phức tạp không cần thiết
Ngay cả các mẫu cơ bản như mối quan hệ producer-consumer sử dụng Queue của asyncio cũng có vấn đề. Việc triển khai queue không xử lý các tình huống phổ biến một cách nhẹ nhàng, chẳng hạn như báo hiệu đúng cách khi không có thêm mục nào được tạo ra. Điều này dẫn đến các điều kiện race và ứng dụng bị treo, buộc các nhà phát triển phải triển khai các giải pháp phức tạp cho những gì vốn nên là các mẫu giao tiếp đơn giản.
Cộng đồng tìm kiếm các giải pháp thay thế tốt hơn
Cộng đồng Python đang tích cực thảo luận về các giải pháp thay thế cho cách tiếp cận của asyncio . Một số nhà phát triển ủng hộ giải pháp monkey-patching của gevent , cho phép cùng một mã hoạt động trong cả ngữ cảnh đồng bộ và bất đồng bộ. Những người khác chỉ ra các ngôn ngữ như Go , xử lý đồng thời mà không gặp vấn đề function coloring làm phiền asyncio .
Tôi thực sự ước cộng đồng đã hợp nhất xung quanh gevent - không có async/await, thay vào đó mọi thứ có thể chặn trong thư viện chuẩn đều được monkey-patch để nhường chỗ cho vòng lặp sự kiện.
Cuộc thảo luận cũng đề cập đến những lo ngại rộng hơn về sự phát triển của Python . Nhiều nhà phát triển cảm thấy rằng Python đã trở nên cồng kềnh với các tính năng như asyncio , type hints và pattern matching được thêm vào để theo kịp các ngôn ngữ khác nhưng không tích hợp tốt với triết lý cốt lõi của Python .
Các Lựa Chọn Thay Thế Được Cộng Đồng Đề Xuất
- gevent: Phương pháp monkey-patching cho phép sử dụng cùng một code cho cả sync/async
- anyio: Lớp giao diện trên asyncio để khắc phục những thiếu sót
- Concurrency kiểu Go: Các ngôn ngữ không gặp vấn đề "function coloring"
- Stackful coroutines: Tương tự như implementation của Lua thay vì stackless
Con đường phía trước vẫn chưa rõ ràng
Trong khi các thư viện như anyio cố gắng cung cấp các giao diện tốt hơn trên asyncio , các vấn đề thiết kế cơ bản vẫn còn. Một số thành viên cộng đồng đề xuất rằng Python cần một bản nâng cấp phiên bản lớn để giải quyết các vấn đề này một cách đúng đắn, tương tự như cách quá trình chuyển đổi từ Python 2 sang 3 đã cho phép các thay đổi đột phá. Tuy nhiên, sự phức tạp của một công việc như vậy và các bài học kinh nghiệm từ cuộc di chuyển khó khăn đó khiến nó không có khả năng xảy ra trong tương lai gần.
Tình hình asyncio làm nổi bật một thách thức rộng hơn trong thiết kế ngôn ngữ: làm thế nào để thêm các tính năng hiện đại mà không ảnh hưởng đến sự đơn giản và thanh lịch đã làm cho ngôn ngữ trở nên phổ biến ngay từ đầu. Hiện tại, các nhà phát triển Python phải làm việc xung quanh các hạn chế của asyncio hoặc xem xét các cách tiếp cận thay thế cho lập trình đồng thời.