6.8 — 6. Common Pitfalls
Chín cái bẫy, phần lớn không gây lỗi biên dịch và không gây lỗi trên máy dev. Chúng chỉ xuất hiện khi có tải thật: Task.Run bọc quanh I/O đồng bộ làm giảm khả năng chịu tải chứ không tăng; lambda async truyền vào tham số Action lặng lẽ trở thành async void; Select(async ...) trả về IEnumerable<Task> lười biếng có thể chạy hai lần; và List<T> cập nhật từ nhiều task song song thì im lặng mất phần tử thay vì báo lỗi. Bài này là danh sách rà soát trước khi đưa code async lên production.
Mục tiêu bài học
Sau bài này bạn có thể:
- Phân biệt sync-over-async và async-over-sync, và biết cả hai đều sai.
- Nhận ra
async voidở những nơi nó không hiện ra trong chữ ký. - Giải thích vì sao
Task.Runkhông tăng throughput cho ASP.NET Core. - Viết đúng khi cần khoá quanh một thao tác async.
- Rà một pull request async và chỉ ra vấn đề trước khi nó lên production.
Nội dung bài học
6.8.1 — Bẫy 1: sync-over-async (.Result, .Wait())
public string GetName(int id) => GetCustomerAsync(id).Result; // SAI
Deadlock trong ASP.NET Framework và WPF; trong ASP.NET Core thì không deadlock nhưng vẫn chiếm một thread pool thread để ngồi không — đúng thứ async sinh ra để tránh.
Cách chữa là async lên tới tận trên cùng. Cơ chế deadlock đã mổ xẻ ở bài 6.4 và trong bài Gọi .Result khi nào thì deadlock.