Jadi saya baru-baru ini diberi tahu bahwa cara saya menggunakan .ContinueWith untuk Tasks bukanlah cara yang tepat untuk menggunakannya. Saya belum menemukan buktinya di internet jadi saya akan bertanya kepada kalian dan melihat apa jawabannya. Berikut adalah contoh cara saya menggunakan .ContinueWith:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
}
Sekarang saya tahu ini adalah contoh sederhana dan akan berjalan sangat cepat, tetapi anggap saja setiap tugas melakukan operasi yang lebih lama. Jadi, apa yang saya diberitahu adalah bahwa di .ContinueWith, Anda perlu mengatakan prevTask.Wait (); jika tidak, Anda bisa melakukan pekerjaan sebelum tugas sebelumnya selesai. Apakah itu mungkin? Saya berasumsi tugas kedua & ketiga saya hanya akan berjalan setelah tugas sebelumnya selesai.
Apa yang saya diberitahu bagaimana menulis kode:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 3");
});
}
sumber
Jawaban:
Ehhh .... Saya pikir beberapa jawaban saat ini kehilangan sesuatu: apa yang terjadi dengan pengecualian?
Satu-satunya alasan Anda memanggil
Wait
sebuah kelanjutan adalah untuk mengamati pengecualian potensial dari anteseden dalam kelanjutan itu sendiri. Pengamatan yang sama akan terjadi jika Anda mengaksesResult
dalam kasus aTask<T>
dan juga jika Anda mengaksesException
properti secara manual . Terus terang, saya tidak akan meneleponWait
atau mengaksesResult
karena jika ada pengecualian Anda akan membayar harga untuk menaikkannya kembali yang merupakan biaya overhead yang tidak perlu. Sebagai gantinya Anda bisa memeriksaIsFaulted
properti dari antesedenTask
. Alternatifnya, Anda dapat membuat alur kerja bercabang dengan merangkai beberapa lanjutan saudara yang hanya diaktifkan berdasarkan keberhasilan atau kegagalan denganTaskContinuationOptions.OnlyOnRanToCompletion
danTaskContinuationOptions.OnlyOnFaulted
.Sekarang, Anda tidak perlu mengamati pengecualian anteseden dalam lanjutan, tetapi Anda mungkin tidak ingin alur kerja Anda bergerak maju jika, katakanlah, "Langkah 1" gagal. Dalam hal ini: menentukan panggilan
TaskContinuationOptions.NotOnFaulted
AndaContinueWith
akan mencegah logika kelanjutan bahkan tidak aktif.Ingatlah bahwa, jika kelanjutan Anda sendiri tidak mengamati pengecualian, orang yang menunggu alur kerja keseluruhan ini untuk menyelesaikannya akan menjadi orang yang mengamatinya. Entah mereka sedang berada
Wait
diTask
hulu atau telah mengikuti kelanjutan mereka sendiri untuk mengetahui kapan itu selesai. Jika yang terakhir, kelanjutannya perlu menggunakan logika observasi yang disebutkan di atas.sumber
TaskContinuationOptions
Anda menggunakannya dengan benar.
Sumber: Metode Task.ContinueWith (Tindakan sebagai MSDN)
Harus memanggil
prevTask.Wait()
dalam setiapTask.ContinueWith
pemanggilan tampaknya seperti cara yang aneh untuk mengulangi logika yang tidak perlu - yaitu melakukan sesuatu untuk menjadi "sangat yakin duper" karena Anda sebenarnya tidak memahami apa yang dilakukan sedikit kode tertentu. Seperti memeriksa nol hanya untuk melempar diArgumentNullException
tempat yang seharusnya dilemparkan.Jadi, tidak, siapa pun yang memberi tahu Anda itu salah dan mungkin tidak mengerti mengapa
Task.ContinueWith
ada.sumber
Siapa yang memberitahumu?
Mengutip MSDN :
Juga, apa tujuan Continue With jika tidak menunggu tugas sebelumnya selesai?
Anda bahkan dapat mengujinya sendiri:
Task.Factory.StartNew(() => { Console.WriteLine("Step 1"); Thread.Sleep(2000); }) .ContinueWith((prevTask) => { Console.WriteLine("I waited step 1 to be completed!"); }) .ContinueWith((prevTask) => { Console.WriteLine("Step 3"); });
sumber
Dari MSDN pada
Task.Continuewith
Saya pikir cara Anda mengharapkannya bekerja pada contoh pertama adalah cara yang benar.
sumber
Anda mungkin juga ingin mempertimbangkan untuk menggunakan Task.Run daripada Task.Factory.StartNew.
Postingan blog Stephen Cleary dan postingan Stephen Toub yang dia referensikan menjelaskan perbedaannya. Ada juga pembahasan dalam jawaban ini .
sumber
Dengan Mengakses
Task.Result
Anda sebenarnya melakukan logika yang mirip dengantask.wait
sumber
Saya akan mengulangi apa yang sudah dibicarakan banyak orang,
prevTask.Wait()
tidak perlu .Untuk contoh lainnya, kita dapat pergi ke Chaining Tasks menggunakan Continuation Tasks , tautan lain oleh Microsoft dengan contoh yang bagus.
sumber