Bagaimana saya bisa membatasi Parallel.ForEach?

295

Saya memiliki loop async Parallel.ForEach () yang saya gunakan untuk mengunduh beberapa halaman web. Bandwidth saya terbatas sehingga saya hanya dapat mengunduh x halaman per waktu tetapi Parallel.ForEach mengeksekusi seluruh daftar halaman web yang diinginkan.

Apakah ada cara untuk membatasi nomor utas atau pembatas lainnya saat menjalankan Parallel.ForEach?

Kode demo:

Parallel.ForEach(listOfWebpages, webpage => {
  Download(webpage);
});

Tugas sebenarnya tidak ada hubungannya dengan halaman web, jadi solusi perayapan web yang kreatif tidak akan membantu.

eugeneK
sumber
@ jKlaus Jika daftar ini tidak diubah, misalnya hanya seperangkat URL, saya tidak bisa melihat masalahnya?
Shiv
@ Shiv, diberikan waktu yang cukup Anda akan ... Hitung jumlah eksekusi Anda dan bandingkan dengan jumlah daftar.
jKlaus
@ jKlaus Apa yang Anda katakan salah?
Shiv
1
@ jKlaus Anda memodifikasi elemen non-threadsafe (integer). Saya berharap itu tidak berhasil dalam skenario itu. OP di sisi lain tidak mengubah apa pun yang perlu di-threadsafe.
Shiv
2
@ jKlaus Ini adalah contoh Parallel.ForEach yang mengatur penghitungan dengan benar> dotnetfiddle.net/moqP2C . Tautan MSDN: msdn.microsoft.com/en-us/library/dd997393(v=vs.110).aspx
jhamm

Jawaban:

564

Anda dapat menentukan MaxDegreeOfParallelismdalam ParallelOptionsparameter:

Parallel.ForEach(
    listOfWebpages,
    new ParallelOptions { MaxDegreeOfParallelism = 4 },
    webpage => { Download(webpage); }
);

MSDN: Paralel. ForEach

MSDN: ParallelOptions.MaxDegreeOfParallelism

Nicholas Butler
sumber
59
Ini mungkin tidak berlaku untuk kasus khusus ini tapi saya pikir saya akan membuangnya kalau-kalau ada orang yang bertanya-tanya tentang hal ini dan menemukan itu berguna. Di sini saya menggunakan 75% (dibulatkan) dari jumlah prosesor. var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 1.0)) };
jKlaus
4
Hanya untuk menyelamatkan orang lain yang harus mencarinya di dokumentasi, memberikan nilai -1sama dengan tidak menetapkannya sama sekali: "Jika [nilai] adalah -1, tidak ada batasan jumlah operasi yang dijalankan secara bersamaan"
stuartd
Tidak jelas bagi saya dari dokumentasi - apakah pengaturan MaxDegreeOfParallelism ke 4 (misalnya) berarti akan ada 4 utas yang masing-masing menjalankan 1/4 dari pengulangan loop (satu putaran dari 4 utas dikirim), atau apakah setiap utas masih melakukan satu loop iterasi dan kami hanya membatasi berapa banyak yang berjalan secara paralel?
Hashman
7
Untuk menjadi jelas inti dan utas bukan hal yang sama. Bergantung pada CPU, ada jumlah thread yang berbeda per core, biasanya 2 per core. Misalnya, jika Anda memiliki CPU 4 inti dengan 2 utas per inti, maka Anda memiliki maksimal 8 utas. Untuk menyesuaikan komentar @jKlaus var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 2.0)) };. Tautan ke utas vs. inti - askubuntu.com/questions/668538/…
TheMiddleMan
41

Anda dapat menggunakan ParallelOptions dan mengatur MaxDegreeOfParallelism untuk membatasi jumlah utas bersamaan:

Parallel.ForEach(
    listOfwebpages, 
    new ParallelOptions{MaxDegreeOfParallelism=2}, 
    webpage => {Download(webpage);});     
rikitikitik
sumber
21

Gunakan overload lain Parallel.Foreachyang membutuhkan ParallelOptionsinstance, dan atur MaxDegreeOfParallelismuntuk membatasi berapa banyak instance yang dieksekusi secara paralel.

Richard
sumber
11

Dan untuk pengguna VB.net (sintaks aneh dan sulit ditemukan) ...

Parallel.ForEach(listOfWebpages, New ParallelOptions() With {.MaxDegreeOfParallelism = 8}, Sub(webpage)
......end sub)  
pengguna3496060
sumber