Apa perbedaan antara menggunakan Parallel.ForEach atau Task.Run () untuk memulai serangkaian tugas secara tidak sinkron?
Versi 1:
List<string> strings = new List<string> { "s1", "s2", "s3" };
Parallel.ForEach(strings, s =>
{
DoSomething(s);
});
Versi 2:
List<string> strings = new List<string> { "s1", "s2", "s3" };
List<Task> Tasks = new List<Task>();
foreach (var s in strings)
{
Tasks.Add(Task.Run(() => DoSomething(s)));
}
await Task.WhenAll(Tasks);
c#
async-await
parallel.foreach
Petter T
sumber
sumber
Task.WaitAll
sebagai penggantiTask.WhenAll
.Jawaban:
Dalam kasus ini, metode kedua akan secara sinkron menunggu tugas diselesaikan alih-alih diblokir.
Namun, ada kelemahan untuk digunakan
Task.Run
dalam loop-WithParallel.ForEach
, adaPartitioner
yang dibuat untuk menghindari membuat lebih banyak tugas daripada yang diperlukan.Task.Run
akan selalu membuat satu tugas per item (karena Anda melakukan ini), tetapiParallel
kumpulan kelas berfungsi sehingga Anda membuat lebih sedikit tugas daripada total item pekerjaan. Ini dapat memberikan kinerja keseluruhan yang jauh lebih baik, terutama jika loop body memiliki sejumlah kecil pekerjaan per item.Jika demikian, Anda dapat menggabungkan kedua opsi dengan menulis:
Perhatikan bahwa ini juga dapat ditulis dalam bentuk yang lebih pendek ini:
sumber
DoSomething
ituasync void DoSomething
?async Task DoSomething
?Versi pertama akan secara sinkron memblokir utas panggilan (dan menjalankan beberapa tugas di atasnya).
Jika ini adalah utas UI, ini akan membekukan UI.
Versi kedua akan menjalankan tugas secara tidak sinkron di kumpulan utas dan melepaskan utas panggilan sampai selesai.
Ada juga perbedaan dalam algoritma penjadwalan yang digunakan.
Perhatikan bahwa contoh kedua Anda dapat disingkat menjadi
sumber
await Task.WhenAll(strings.Select(async s => await Task.Run(() => DoSomething(s)));
? Saya memiliki masalah ketika mengembalikan tugas (bukannya menunggu) terutama ketika pernyataan sepertiusing
terlibat untuk membuang objek.Saya akhirnya melakukan ini, karena rasanya lebih mudah dibaca:
sumber
Saya telah melihat Paralel. ForEach digunakan secara tidak tepat, dan saya menemukan contoh dalam pertanyaan ini akan membantu.
Saat Anda menjalankan kode di bawah ini di aplikasi Konsol, Anda akan melihat bagaimana tugas dieksekusi dalam Paralel. FOREach tidak memblokir utas panggilan. Ini bisa baik-baik saja jika Anda tidak peduli dengan hasilnya (positif atau negatif) tetapi jika Anda memang membutuhkan hasilnya, Anda harus memastikan untuk menggunakan Task.WhenAll.
Inilah hasilnya:
Kesimpulan:
Menggunakan Paralel. FOREach dengan Tugas tidak akan memblokir utas panggilan. Jika Anda peduli dengan hasilnya, pastikan untuk menunggu tugas.
~ Ceria
sumber