Saya menggunakan klien API yang sepenuhnya asynchrounous, yaitu setiap operasi baik kembali Task
atau Task<T>
, misalnya:
static async Task DoSomething(int siteId, int postId, IBlogClient client)
{
await client.DeletePost(siteId, postId); // call API client
Console.WriteLine("Deleted post {0}.", siteId);
}
Dengan menggunakan operator async / await C # 5, apa cara yang benar / paling efisien untuk memulai banyak tugas dan menunggu semuanya selesai:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
atau:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
Karena klien API menggunakan HttpClient secara internal, saya berharap ini akan segera mengeluarkan 5 permintaan HTTP, menulis ke konsol setelah masing-masing selesai.
c#
.net
task-parallel-library
async-await
c#-5.0
Ben Foster
sumber
sumber
Jawaban:
Meskipun Anda menjalankan operasi secara paralel dengan kode di atas, kode ini memblokir setiap utas yang menjalankan setiap operasi. Misalnya, jika panggilan jaringan membutuhkan waktu 2 detik, setiap utas hang selama 2 detik tanpa melakukan apa-apa selain menunggu.
Di sisi lain, kode di atas dengan
WaitAll
juga memblokir utas dan utas Anda tidak akan bebas untuk memproses pekerjaan lain sampai operasi berakhir.Pendekatan yang Disarankan
Saya lebih suka
WhenAll
yang akan melakukan operasi Anda secara sinkron secara paralel.Untuk mendukung hal ini, berikut adalah posting blog terperinci yang membahas semua alternatif dan keuntungan / kerugiannya: Bagaimana dan Di mana Concurrent I / O Asinkron dengan API Web ASP.NET
sumber
WaitAll
juga memblokir utas" - bukan hanya memblokir satu utas, yang disebutWaitAll
?Saya ingin melihat hasil dari metode yang disediakan dalam pertanyaan serta jawaban yang diterima, jadi saya mengujinya.
Berikut kodenya:
Dan output yang dihasilkan:
sumber
Karena API yang Anda panggil adalah async,
Parallel.ForEach
versi itu tidak masuk akal. Anda tidak boleh menggunakan.Wait
dalamWaitAll
versi karena itu akan kehilangan paralelisme Alternatif lain jika pemanggil adalah async gunakanTask.WhenAll
setelah melakukanSelect
danToArray
untuk menghasilkan berbagai tugas. Alternatif kedua menggunakan Rx 2.0sumber
Anda dapat menggunakan
Task.WhenAll
fungsi yang dapat Anda lewati dan tugas;Task.WhenAll
akan mengembalikan tugas yang selesai saat semua tugas yang AndaTask.WhenAll
selesaikan selesai. Anda harus menunggu secara tidak sinkronTask.WhenAll
agar Anda tidak akan memblokir utas UI Anda:sumber
Parallel.ForEach
membutuhkan daftar pekerja yang ditentukan pengguna dan non-asyncAction
untuk melakukan dengan masing-masing pekerja.Task.WaitAll
danTask.WhenAll
memerlukanList<Task>
, yang menurut definisi tidak sinkron.Saya menemukan RiaanDP 's respon sangat berguna untuk memahami perbedaan, tapi perlu koreksi untuk
Parallel.ForEach
. Reputasi tidak cukup untuk menanggapi komentarnya, demikian tanggapan saya sendiri.Output yang dihasilkan di bawah ini. Waktu eksekusi dapat dibandingkan. Saya menjalankan tes ini ketika komputer saya melakukan pemindaian anti virus mingguan. Mengubah urutan pengujian memang mengubah waktu pelaksanaannya.
sumber