ValueTask<T>
không phải là một tập hợp con Task<T>
, nó là một superset .
ValueTask<T>
là một liên kết phân biệt của T và a Task<T>
, làm cho nó không phân bổ ReadAsync<T>
để trả về đồng bộ một giá trị T có sẵn (ngược lại với việc sử dụng Task.FromResult<T>
, cần phân bổ một Task<T>
thể hiện). ValueTask<T>
là đáng chờ đợi, vì vậy hầu hết các trường hợp tiêu thụ sẽ không thể phân biệt được với a Task<T>
.
ValueTask, là một cấu trúc, cho phép viết các phương thức không đồng bộ không phân bổ bộ nhớ khi chúng chạy đồng bộ mà không ảnh hưởng đến tính nhất quán của API. Hãy tưởng tượng có một giao diện với phương thức trả về tác vụ. Mỗi lớp thực hiện giao diện này phải trả về một Tác vụ ngay cả khi chúng xảy ra để thực thi đồng bộ (hy vọng sử dụng Task.FromResult). Tất nhiên, bạn có thể có 2 phương thức khác nhau trên giao diện, một phương thức đồng bộ và một phương thức không đồng bộ nhưng điều này đòi hỏi 2 cách triển khai khác nhau để tránh đồng bộ hóa qua async và async trên đồng bộ hóa.
Vì vậy, nó cho phép bạn viết một phương thức không đồng bộ hoặc đồng bộ, thay vào đó viết một phương thức giống hệt nhau cho mỗi phương thức. Bạn có thể sử dụng nó ở bất cứ đâu bạn sử dụng Task<T>
nhưng thường không thêm bất cứ thứ gì.
Vâng, nó bổ sung thêm một điều: Nó thêm một lời hứa ngụ ý cho người gọi rằng phương thức này thực sự sử dụng chức năng bổ sung ValueTask<T>
cung cấp. Cá nhân tôi thích chọn các loại tham số và trả về cho người gọi càng nhiều càng tốt. Đừng quay lại IList<T>
nếu bảng liệt kê không thể cung cấp số đếm; Đừng quay lại IEnumerable<T>
nếu có thể. Người tiêu dùng của bạn không cần phải tra cứu bất kỳ tài liệu nào để biết phương pháp nào của bạn có thể được gọi một cách hợp lý và phương pháp nào không thể.
Tôi không thấy những thay đổi thiết kế trong tương lai là một lập luận thuyết phục ở đó. Hoàn toàn ngược lại: Nếu một phương thức thay đổi ngữ nghĩa của nó, nó sẽ phá vỡ bản dựng cho đến khi tất cả các lệnh gọi đến nó được cập nhật tương ứng. Nếu điều đó được coi là không mong muốn (và tin tôi đi, tôi đồng cảm với mong muốn không phá vỡ bản dựng), hãy xem xét phiên bản giao diện.
Đây thực chất là những gì gõ mạnh là dành cho.
Nếu một số lập trình viên thiết kế các phương thức không đồng bộ trong cửa hàng của bạn không thể đưa ra quyết định sáng suốt, có thể hữu ích khi chỉ định một cố vấn cao cấp cho mỗi lập trình viên ít kinh nghiệm hơn và xem xét mã hàng tuần. Nếu họ đoán sai, giải thích tại sao nó nên được thực hiện khác nhau. Đó là chi phí dành cho những người đàn anh, nhưng nó sẽ giúp các đàn em tăng tốc nhanh hơn nhiều so với việc ném họ vào tận cùng và cho họ một số quy tắc tùy tiện để tuân theo.
Nếu anh chàng viết phương pháp này không biết liệu nó có thể được gọi một cách đồng bộ hay không, thì ai trên trái đất?!
Nếu bạn có nhiều lập trình viên thiếu kinh nghiệm viết các phương thức không đồng bộ, thì những người đó cũng gọi họ như vậy phải không? Họ có đủ điều kiện để tự mình tìm ra cái nào an toàn để gọi async không, hoặc họ sẽ bắt đầu áp dụng quy tắc tùy ý tương tự như cách họ gọi những thứ này?
Vấn đề ở đây không phải là kiểu trả về của bạn, đó là các lập trình viên được đặt vào vai trò mà họ chưa sẵn sàng. Điều đó đã xảy ra vì một lý do, vì vậy tôi chắc chắn rằng nó không thể tầm thường để sửa chữa. Mô tả nó chắc chắn không phải là một giải pháp. Nhưng tìm kiếm một cách để lén vấn đề qua trình biên dịch cũng không phải là một giải pháp.
ValueTask<T>
(về mặt phân bổ) không cụ thể hóa cho các hoạt động thực sự không đồng bộ (vì trong trường hợpValueTask<T>
đó vẫn sẽ cần phân bổ heap). Ngoài ra còn có vấn đềTask<T>
có rất nhiều hỗ trợ khác trong các thư viện.