Saat ini saya membaca " Concurrency in C # Cookbook " oleh Stephen Cleary, dan saya memperhatikan teknik berikut:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTask
adalah panggilan ke httpclient.GetStringAsync
, dan timeoutTask
sedang dijalankan Task.Delay
.
Jika tidak waktu tunggu, maka downloadTask
sudah selesai. Mengapa perlu melakukan menunggu kedua daripada kembali downloadTask.Result
, mengingat tugas sudah selesai?
c#
asynchronous
async-await
task
julio.g
sumber
sumber
downloadTask
dantimeoutTask
? Apa yang mereka lakukan?AggregateException
denganResult
pengecualian pertama vs melaluiExceptionDispatchInfo
denganawait
). Dibahas secara lebih rinci dalam Stephen Toub "Penanganan Pengecualian Tugas di .NET 4.5": blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )Jawaban:
Sudah ada beberapa jawaban / komentar yang bagus di sini, tetapi hanya untuk berpadu ...
Ada dua alasan mengapa saya lebih memilih
await
lebihResult
(atauWait
). Yang pertama adalah bahwa penanganan error berbeda;await
tidak membungkus pengecualian dalamAggregateException
. Idealnya, kode asynchronous tidak harus berurusanAggregateException
sama sekali, kecuali jika secara khusus menginginkannya .Alasan kedua sedikit lebih halus. Seperti yang saya jelaskan di blog saya (dan di buku),
Result
/Wait
dapat menyebabkan kebuntuan , dan dapat menyebabkan kebuntuan yang lebih halus lagi saat digunakan dalam suatuasync
metode . Jadi, ketika saya membaca kode dan saya melihatResult
atauWait
, itu adalah tanda peringatan langsung. TheResult
/Wait
hanya benar jika Anda benar-benar yakin bahwa tugas sudah selesai. Ini tidak hanya sulit dilihat secara sekilas (dalam kode dunia nyata), tetapi juga lebih rentan terhadap perubahan kode.Itu bukan untuk mengatakan bahwa
Result
/Wait
harus tidak pernah digunakan. Saya mengikuti pedoman ini dalam kode saya sendiri:await
.Result
/Wait
jika kode benar-benar memanggilnya. Penggunaan seperti itu mungkin harus memiliki komentar.Result
danWait
.Perhatikan bahwa (1) sejauh ini merupakan kasus umum, oleh karena itu saya cenderung menggunakan di
await
mana-mana dan memperlakukan kasus lain sebagai pengecualian dari aturan umum.sumber
await
mencegahAggregateException
pembungkusnya.AggregateException
dirancang untuk pemrograman paralel, bukan pemrograman asinkron.Wait
adalah untuk bergabung dengan instance Dynamic Task ParallelismTask
. Menggunakannya untuk menungguTask
instance asinkron berbahaya. Microsoft mempertimbangkan untuk memperkenalkan jenis "Janji" baru, tetapi memilih untuk menggunakan jenis yang sudah adaTask
; tradeoff dari menggunakan kembaliTask
jenis yang ada untuk tugas asinkron adalah Anda berakhir dengan beberapa API yang seharusnya tidak digunakan dalam kode asinkron.Ini masuk akal jika
timeoutTask
merupakan produkTask.Delay
, yang saya percayai apa yang ada di dalam buku.Task.WhenAny
kembaliTask<Task>
, di mana tugas batin adalah salah satu yang Anda berikan sebagai argumen. Bisa ditulis ulang seperti ini:Dalam kedua kasus tersebut, karena
downloadTask
telah selesai, ada perbedaan yang sangat kecil antarareturn await downloadTask
danreturn downloadTask.Result
. DiAggregateException
sinilah yang terakhir akan membuang yang membungkus pengecualian asli apa pun, seperti yang ditunjukkan oleh @KirShlenskiy di komentar. Yang pertama hanya akan membuang pengecualian aslinya.Dalam kedua kasus tersebut, di mana pun Anda menangani pengecualian, Anda harus memeriksa
AggregateException
dan pengecualian dalamnya, untuk mengetahui penyebab kesalahan.sumber