Apa gunanya untuk Task.FromResult <TResult> di C #


189

Di C # dan TPL ( Perpustakaan Tugas Paralel ), Taskkelas mewakili pekerjaan yang sedang berlangsung yang menghasilkan nilai tipe T.

Saya ingin tahu apa perlunya metode Task.FromResult ?

Yaitu: Dalam skenario di mana Anda sudah memiliki nilai yang dihasilkan, apa perlunya membungkusnya kembali menjadi Tugas?

Satu-satunya hal yang terlintas dalam pikiran adalah bahwa itu digunakan sebagai beberapa adaptor untuk metode lain menerima contoh Tugas.



30
Sampai taraf tertentu saya setuju dengan itu, tetapi pembuatan halaman yang padat, bermanfaat, terkonsolidasi, dan berorientasi diskusi seperti ini adalah manfaat besar. Saya hampir selalu belajar lebih banyak dari halaman stackoverflow yang bagus dan padat daripada dari googling dan melakukan penelitian di berbagai tempat, jadi dalam hal ini, saya sangat senang dia memposting ini.
Alex Edelstein

41
Saya pikir Google membawa saya ke SO dan SO meminta saya untuk pergi ke Google. Ini adalah referensi melingkar :)
pengguna gmail

Jawaban:


258

Ada dua kasus penggunaan umum yang saya temukan:

  1. Saat Anda mengimplementasikan antarmuka yang memungkinkan penelepon tidak sinkron, namun penerapan Anda sinkron.
  2. Saat Anda mematikan / mengejek kode asinkron untuk pengujian.

6
Kasus yang bagus untuk # 1 adalah layanan web. Anda dapat memiliki metode layanan sinkron yang mengembalikan Task.FromResultdan klien yang menunggu secara tidak sinkron untuk I / O jaringan. Dengan cara ini Anda dapat berbagi antarmuka yang sama antara klien / server menggunakan ChannelFactory.
Nelson Rothermel

2
Misalnya metode ChallengeAsync. WTF adalah desainer di MS berpikir? Sama sekali tidak ada alasan untuk metode ini untuk mengembalikan Tugas. Dan semua kode sampel dari MS hanya memiliki FromResult (0). Semoga kompiler cukup pintar untuk mengoptimalkan ini, dan tidak benar-benar menelurkan utas baru dan kemudian membunuhnya segera!
John Henckel

14
@JohnHenckel: OWIN dirancang dari bawah ke atas agar ramah-lingkungan. Antarmuka dan kelas dasar sering menggunakan tanda tangan async karena hanya memungkinkan (bukan memaksa ) implementasi menjadi async. Jadi ini mirip dengan IEnumerable<T>berasal dari IDisposable- memungkinkan enumerable untuk memiliki sumber daya sekali pakai, bukan memaksanya . Baik FromResult,, asyncjuga tidak awaitakan menelurkan utas.
Stephen Cleary

4
@StephenCleary hmhm, terima kasih sudah menjelaskannya. Saya berasumsi bahwa menunggu akan muncul, tetapi saya mencobanya dan ternyata tidak. Hanya Task.Run yang melakukannya. Oleh karena itu, x = menunggu Task.FromResult (0); sama dengan mengatakan x = 0; itu membingungkan, tapi senang tahu!
John Henckel

4
@OlegI: Untuk operasi I / O, solusi terbaik adalah mengimplementasikannya secara tidak sinkron, tetapi terkadang Anda tidak memiliki pilihan itu. Juga, kadang-kadang Anda dapat mengimplementasikannya secara sinkron (misalnya, hasil dalam cache, kembali ke implementasi asinkron jika nilainya tidak di-cache). Secara umum, Taskmetode -mengembalikan berarti " mungkin tidak sinkron". Jadi kadang-kadang metode diberi tanda tangan asinkron yang sepenuhnya tahu bahwa beberapa implementasi akan sinkron (misalnya, NetworkStreamharus async, tetapi MemoryStreamharus disinkronkan).
Stephen Cleary

50

Salah satu contoh akan menjadi metode yang menggunakan cache. Jika hasilnya sudah dihitung, Anda bisa mengembalikan tugas yang selesai dengan nilai (menggunakanTask.FromResult ). Jika tidak, maka Anda melanjutkan dan mengembalikan tugas yang mewakili pekerjaan yang sedang berlangsung.

Contoh Cache: Contoh Cache menggunakan Task.FromResult untuk nilai yang dihitung sebelumnya


Dan menyelesaikan tugas, seperti yang dikembalikan dari Task.FromResult, bisa di-cache.
Paulo Morgado

1
@ Paulo: menjaga seluruh objek Tugas dalam memori tampaknya jauh lebih boros daripada hanya caching hasilnya.
Ben Voigt

2
"Nilai tugas" yang diharapkan sudah di-cache. Saya tidak ingat persis yang mana, tapi saya pikir Task.FromResult(0), Task.FromResult(1), Task.FromResult(false)dan Task.FromResult(true)cache. Anda tidak seharusnya melakukan cache tugas untuk akses jaringan tetapi satu dari hasil sangat baik. Apakah Anda lebih suka membuatnya setiap kali Anda perlu mengembalikan nilainya?
Paulo Morgado

4
... dan untuk menjawab pertanyaan saya sendiri, manfaat dari cache Tugas adalah beberapa tugas dapat diselesaikan, dan yang lainnya bisa menjadi tugas yang belum selesai. Penelepon tidak harus peduli: mereka melakukan panggilan tidak sinkron, dan jika sudah selesai, mereka mendapat jawaban segera ketika mereka menunggu, jika tidak, mereka mendapatkannya nanti. Tanpa tugas-tugas yang di-cache ini, apakah (a) membutuhkan dua mekanisme yang berbeda, satu sinkronisasi dan satu async - rumit untuk penelepon, atau (b) harus secara dinamis membuat Tugas, setiap kali seorang penelepon meminta jawaban yang sudah tersedia (jika kami hanya men-cache TResult).
ToolmakerSteve

1
Aku mengerti sekarang. Kata-kata jawabannya agak membingungkan. Tugas itu sendiri tidak memiliki mekanisme "caching" bawaan. Tetapi jika Anda menulis mekanisme caching untuk ... katakan .... mengunduh file, Tugas <File> GetFileAync (), Anda dapat langsung mengembalikan file yang sudah ada dalam cache dengan menggunakan Task.FromResult (cachedFile), dan menunggu akan berjalan secara serempak, menghemat waktu dengan tidak memiliki sakelar ulir.
Brain2000

31

Gunakan saat Anda ingin membuat metode yang bisa ditunggu tanpa menggunakan kata kunci async. Saya menemukan contoh ini:

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);
    }
}

Di sini Anda membuat implementasi antarmuka IHttpActionResult Anda sendiri untuk digunakan dalam Aksi Web Api. Metode ExecuteAsync diharapkan asinkron tetapi Anda tidak harus menggunakan kata kunci async untuk menjadikannya tidak sinkron dan menunggu. Karena Anda sudah memiliki hasilnya dan tidak perlu menunggu apa pun, lebih baik menggunakan Task.Fromult.



4

Gunakan Task.FromResult ketika Anda ingin memiliki operasi yang tidak sinkron tetapi terkadang hasilnya ada di tangan secara sinkron. Anda dapat menemukan contoh yang baik di sini http://msdn.microsoft.com/en-us/library/hh228607.aspx .


dalam sampel Anda yang baik, hasilnya tidak ada di tangan secara serempak, operasi semua async, Task.FromResultdigunakan untuk mendapatkan hasil async yang sebelumnya di-cache.
Rodrigo Reis

1

Saya berpendapat bahwa Anda dapat menggunakan Task.FromResult untuk metode yang sinkron yang membutuhkan waktu lama untuk diselesaikan sementara Anda dapat melakukan pekerjaan independen lainnya dalam kode Anda. Saya lebih suka membuat metode-metode untuk memanggil async. Tetapi bayangkan situasi di mana Anda tidak memiliki kendali atas kode yang dipanggil dan Anda ingin pemrosesan paralel implisit.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.