Việc sử dụng cho Task.FromResult <TResult> trong C # là gì


189

Trong C # và TPL ( Thư viện song song nhiệm vụ ), Tasklớp đại diện cho một công việc đang diễn ra tạo ra giá trị của loại T.

Tôi muốn biết sự cần thiết của phương thức Task.FromResult là gì?

Đó là: Trong một kịch bản mà bạn đã có sẵn giá trị sản xuất, cần phải bọc lại thành Nhiệm vụ là gì?

Điều duy nhất nảy ra trong đầu là nó được sử dụng như một số bộ chuyển đổi cho các phương thức khác chấp nhận một thể hiện của Nhiệm vụ.


4
điều này có giúp gì cho bạn không? msdn.microsoft.com/en-us/l
Library / hh228607.aspx

30
Ở một mức độ nào đó tôi đồng ý với điều đó, nhưng việc tạo ra các trang dày đặc, hữu ích, hợp nhất, định hướng như thế này là một lợi ích rất lớn. Tôi hầu như luôn học hỏi nhiều hơn từ một trang stackoverflow tốt, dày đặc hơn là từ việc tìm kiếm và nghiên cứu trên nhiều nơi, vì vậy trong trường hợp này, tôi thực sự rất vui vì anh ấy đã đăng bài này.
Alex Edelstein

41
Tôi nghĩ rằng Google mang tôi đến SO và SO yêu cầu tôi đến Google. Nó là một tài liệu tham khảo vòng tròn :)
người dùng gmail

Câu trả lời:


257

Có hai trường hợp sử dụng phổ biến mà tôi đã tìm thấy:

  1. Khi bạn đang triển khai một giao diện cho phép người gọi không đồng bộ, nhưng việc triển khai của bạn là đồng bộ.
  2. Khi bạn còn sơ khai / chế nhạo mã không đồng bộ để kiểm tra.

6
Một trường hợp tốt cho # 1 là một dịch vụ web. Bạn có thể có một phương thức dịch vụ đồng bộ trả về Task.FromResultvà một máy khách đang chờ không đồng bộ cho I / O mạng. Bằng cách này, bạn có thể chia sẻ cùng một giao diện giữa máy khách / máy chủ bằng cách sử dụng ChannelFactory.
Nelson Rothermel

2
Ví dụ, phương thức ChallengeAsync. WTF là những nhà thiết kế tại MS nghĩ gì? Hoàn toàn không có lý do cho phương thức này để trả về một Nhiệm vụ. Và tất cả các mã mẫu từ MS chỉ đơn giản là có FromResult (0). Hy vọng trình biên dịch đủ thông minh để tối ưu hóa điều này và không thực sự sinh ra một luồng mới và sau đó giết nó ngay lập tức!
John Henckel

14
@JohnHenckel: OWIN được thiết kế từ đầu để trở nên thân thiện. Các giao diện và các lớp cơ sở thường sử dụng chữ ký async vì nó chỉ cho phép (không bắt buộc ) việc triển khai không đồng bộ. Vì vậy, nó tương tự như IEnumerable<T>xuất phát từ IDisposable- nó cho phép vô số tài nguyên dùng một lần, không ép buộc . Không FromResult, asynccũng awaitsẽ không sinh ra chủ đề.
Stephen Cleary

4
@StephenCleary hmhm, cảm ơn vì đã giải thích điều đó. Tôi đã cho rằng sự chờ đợi sẽ sinh ra, nhưng tôi đã thử và tôi thấy nó không. Chỉ có nhiệm vụ.Run làm. Do đó, x = đang chờ tác vụ.FromResult (0); tương đương với việc nói x = 0; đó là khó hiểu, nhưng tốt để biết!
John Henckel

4
@OlegI: Đối với các thao tác I / O, giải pháp tốt nhất là triển khai nó không đồng bộ, nhưng đôi khi bạn không có lựa chọn đó. Ngoài ra, đôi khi bạn có thể triển khai nó một cách đồng bộ (ví dụ: kết quả được lưu trong bộ nhớ cache, quay lại triển khai không đồng bộ nếu giá trị không được lưu trong bộ nhớ cache). Tổng quát hơn, Taskphương thức quay lại có nghĩa là " thể không đồng bộ". Vì vậy, đôi khi các phương thức được cung cấp một chữ ký không đồng bộ biết rõ rằng một số triển khai sẽ đồng bộ (ví dụ: NetworkStreamnên MemoryStreamkhông đồng bộ , nhưng phải được đồng bộ hóa).
Stephen Cleary

50

Một ví dụ sẽ là một phương thức sử dụng bộ đệm. Nếu kết quả đã được tính toán, bạn có thể trả về một tác vụ đã hoàn thành với giá trị (sử dụng Task.FromResult). Nếu không, sau đó bạn tiếp tục và trả lại một nhiệm vụ đại diện cho công việc đang diễn ra.

Ví dụ về bộ đệm : Ví dụ về bộ đệm bằng cách sử dụng Task.FromResult cho các giá trị được tính toán trước


Và các tác vụ đã hoàn thành, chẳng hạn như các tác vụ được trả về Task.FromResult, có thể được lưu trữ.
Paulo Morgado

1
@Paulo: giữ toàn bộ đối tượng Tác vụ trong bộ nhớ có vẻ lãng phí hơn nhiều so với kết quả bộ đệm.
Ben Voigt

2
Mong đợi "nhiệm vụ giá trị" đã được lưu trữ. Tôi không nhớ chính xác cái nào, nhưng tôi nghĩ Task.FromResult(0), Task.FromResult(1), Task.FromResult(false)Task.FromResult(true)được lưu trữ. Bạn không cần phải lưu trữ một tác vụ để truy cập mạng nhưng một kết quả là hoàn toàn tốt. Bạn có muốn tạo một lần mỗi khi bạn cần trả về giá trị không?
Paulo Morgado

4
... Và để trả lời câu hỏi của riêng tôi, lợi ích của bộ đệm của Nhiệm vụ là một số trong số chúng có thể được hoàn thành và một số khác có thể chưa hoàn thành. Người gọi không cần phải quan tâm: họ thực hiện cuộc gọi không đồng bộ và nếu nó đã hoàn thành, họ sẽ nhận được câu trả lời ngay lập tức khi họ chờ đợi, nếu không, họ sẽ nhận được sau. Nếu không có các tác vụ được lưu trong bộ nhớ cache này, (a) sẽ yêu cầu hai cơ chế khác nhau, một đồng bộ hóa và một không đồng bộ - cồng kềnh cho người gọi hoặc (b) phải tự động tạo một Tác vụ, mỗi khi người gọi yêu cầu một câu trả lời đã có sẵn (nếu chúng tôi chỉ lưu vào bộ đệm).
ToolmakerSteve

1
Bây giờ tôi hiểu rồi. Từ ngữ của câu trả lời hơi khó hiểu. Bản thân tác vụ không có cơ chế "lưu vào bộ nhớ cache". Nhưng nếu bạn đã viết một cơ chế lưu trữ cho ... giả sử .... tải xuống tệp, Tác vụ <Tệp> GetFileAync (), bạn có thể ngay lập tức trả lại một tệp đã có trong bộ đệm bằng cách sử dụng Task.FromResult (cacheedFile) và chờ đợi sẽ chạy đồng bộ, tiết kiệm thời gian bằng cách không có công tắc luồng.
Brain2000

31

Sử dụng nó khi bạn muốn tạo một phương thức chờ đợi mà không cần sử dụng từ khóa async. Tôi tìm thấy ví dụ này:

public class TextResult : IHttpActionResult
{
    string _value;
    HttpRequestMessage _request;

    public TextResult(string value, HttpRequestMessage request)
    {
        _value = value;
        _request = request;
    }
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage()
        {
            Content = new StringContent(_value),
            RequestMessage = _request
        };
        return Task.FromResult(response);
    }
}

Tại đây, bạn đang tạo triển khai riêng của mình về giao diện IHttpActionResult sẽ được sử dụng trong Web Api Action. Phương thức ExecuteAsync được dự kiến ​​là không đồng bộ nhưng bạn không phải sử dụng từ khóa async để làm cho nó không đồng bộ và được chờ đợi. Vì bạn đã có kết quả và không cần chờ đợi bất cứ điều gì tốt hơn nên sử dụng Task.FromResult.



4

Sử dụng Task.FromResult khi bạn muốn có một hoạt động không đồng bộ nhưng đôi khi kết quả là có trong tay một cách đồng bộ. Bạn có thể tìm thấy một mẫu tốt ở đây http://msdn.microsoft.com/en-us/l Library / hh228607.aspx .


trong mẫu tốt của bạn, kết quả không có trong tay một cách đồng bộ, hoạt động hoàn toàn không đồng bộ, Task.FromResultđược sử dụng để có được kết quả không đồng bộ được lưu trong bộ nhớ cache trước đó.
Rodrigo Reis

1

Tôi sẽ lập luận rằng bạn có thể sử dụng Task.FromResult cho các phương thức đồng bộ mất nhiều thời gian để hoàn thành trong khi bạn có thể thực hiện các công việc độc lập khác trong mã của mình. Id thay vì thực hiện các phương thức để gọi async mặc dù. Nhưng hãy tưởng tượng tình huống mà bạn không có quyền kiểm soát mã được gọi và bạn muốn xử lý song song ngầm đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.