Bu foreach kodunu Parallel.ForEach'a nasıl dönüştürebilirim?


180

Biraz kafam karıştı Parallel.ForEach.
Nedir Parallel.ForEachve tam olarak ne yapar?
Lütfen herhangi bir MSDN bağlantısına başvurmayın.

İşte basit bir örnek:

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);

foreach (string line in list_lines)
{
    //My Stuff
}

Bu örneği nasıl yeniden yazabilirim Parallel.ForEach?


Bu soruya şu yanıt verilmiş olabilir stackoverflow.com/questions/3789998/…
Ujjwal Manandhar

1
@UjjwalManandhar Bu aslında oldukça farklı, çünkü Parallelsınıf ve PLINQ kullanımı arasındaki farkı soruyor .
Reed Copsey

18
Diğerleri nasıl yeniden yazabileceğinizi yanıtladı. Peki ne yapıyor? Tıpkı normalde olduğu gibi koleksiyondaki her öğe için bir "işlem" yapar foreach. Aradaki fark, paralel sürümün aynı anda birçok "eylem" yapabilmesidir. Çoğu durumda (kodu hangi bilgisayarın çalıştırdığına ve ne kadar meşgul olduğuna ve diğer şeylere bağlı olarak) daha hızlı olacaktır ve bu en önemli avantajdır. Paralel olarak yaptığınızda , öğelerin hangi sırayla işlendiğini bilemeyeceğinizi unutmayın . Her zamanki (seri) foreach, lines[0]önce gelen, sonra lines[1]vb. Garantilidir .
Jeppe Stig Nielsen

1
@JeppeStigNielsen Her şeyi daha hızlı olmayacak çünkü işleri paralel hale getirmenin önemli bir yükü var. Yinelediğiniz koleksiyonun boyutuna ve içindeki eyleme bağlıdır. Yapılacak doğru şey Parallel.ForEach () kullanımı ile foreach () kullanımı arasındaki farkı ölçmektir . Çoğu zaman normal bir foreach () daha hızlıdır.
Dave Black

3
@DaveBlack Tabii. Her durumda daha hızlı mı yoksa daha yavaş mı olduğunu ölçmek gerekecek . Sadece genel olarak paralellik tanımlamaya çalışıyordum.
Jeppe Stig Nielsen

Yanıtlar:


126
string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);
Parallel.ForEach(list_lines, line =>
{
    //Your stuff
});

6
Sadece işaret etmek istedim (OP için daha fazla), böylece sadece üzerinde çalıştığı yanlış yönlendirilmiş bir düşünce yoktu List<T>;)
Reed Copsey

1
dikkat ve cevap için teşekkürler. HASH listelerini kullanarak yinelenen öğeleri kaldırma nedeniyle kodlarımda List <string> kullandım. düzenli dizi ile kolayca kopyaları kaldıramazsınız :).
SilverLight

119
Orijinal mesajlar sorusuna hiçbir açıklama olmadığı için ben, bu cevap doğru cevabı olarak işaretlenmiş karıştı ... "Ne Parallel.ForEach olduğunu ve tam olarak ne yapıyor?"
FOSE

6
@fosb Sorun, soru başlığının anlamını tamamen değiştirmek için düzenlendiğidir ... bu yüzden bu cevap artık bir anlam ifade etmiyor. Bunu söyledikten sonra, hala kötü bir cevap
aw04

274

Foreach döngüsü:

  • Yinelemeler sırayla gerçekleşir, tek tek
  • foreach döngüsü tek bir iş parçacığından çalıştırılır.
  • foreach döngüsü .NET'in her çerçevesinde tanımlanır
  • Yürütme yavaş süreçler olabilir yavaş onlar seri çalıştırmak konum olarak,
    • İşlem 2, 1 bitene kadar başlatılamaz. İşlem 3, 2 ve 1 tamamlanana kadar başlatılamaz ...
  • İş parçacığı yükü olmadığından hızlı işlemlerin yürütülmesi daha hızlı olabilir

Parallel.ForEach:

  • İcra paralel olarak gerçekleşir.
  • Parallel.ForEach birden çok İş Parçacığı kullanır.
  • Parallel.ForEach .Net 4.0 ve üzeri çerçevelerde tanımlanmıştır.
  • Yavaş süreçlerin yürütülmesi daha hızlı olabilir onlar paralel olarak çalıştırılabilir olarak,
    • 2, 1 işler, ve 3 olabilir da aynı anda (aşağıdaki örnekte yeniden konuları bakınız)
  • Yürütme hızlı süreçler olabilir yavaş çünkü ek iş parçacığı yükü,

Aşağıdaki örnek, geleneksel foreach döngüsü ile

Parallel.ForEach () Örneği

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace ParallelForEachExample
{
    class Program
    {
        static void Main()
        {
            string[] colors = {
                                  "1. Red",
                                  "2. Green",
                                  "3. Blue",
                                  "4. Yellow",
                                  "5. White",
                                  "6. Black",
                                  "7. Violet",
                                  "8. Brown",
                                  "9. Orange",
                                  "10. Pink"
                              };
            Console.WriteLine("Traditional foreach loop\n");
            //start the stopwatch for "for" loop
            var sw = Stopwatch.StartNew();
            foreach (string color in colors)
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            Console.WriteLine("foreach loop execution time = {0} seconds\n", sw.Elapsed.TotalSeconds);
            Console.WriteLine("Using Parallel.ForEach");
            //start the stopwatch for "Parallel.ForEach"
             sw = Stopwatch.StartNew();
            Parallel.ForEach(colors, color =>
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            );
            Console.WriteLine("Parallel.ForEach() execution time = {0} seconds", sw.Elapsed.TotalSeconds);
            Console.Read();
        }
    }
}

Çıktı

Traditional foreach loop
1. Red, Thread Id= 10
2. Green, Thread Id= 10
3. Blue, Thread Id= 10
4. Yellow, Thread Id= 10
5. White, Thread Id= 10
6. Black, Thread Id= 10
7. Violet, Thread Id= 10
8. Brown, Thread Id= 10
9. Orange, Thread Id= 10
10. Pink, Thread Id= 10
foreach loop execution time = 0.1054376 seconds

Parallel.ForEach örneğini kullanma

1. Red, Thread Id= 10
3. Blue, Thread Id= 11
4. Yellow, Thread Id= 11
2. Green, Thread Id= 10
5. White, Thread Id= 12
7. Violet, Thread Id= 14
9. Orange, Thread Id= 13
6. Black, Thread Id= 11
8. Brown, Thread Id= 10
10. Pink, Thread Id= 12
Parallel.ForEach() execution time = 0.055976 seconds

63
Parallel.ForEach'ın (her zaman) daha hızlı olduğunu iddia ettiğinizle gerçekten aynı fikirde değilim. Bu gerçekten döngü içindeki operasyonun ağırlığına bağlıdır. Bu, paralellizm getirme yükü olabilir veya olmayabilir.
Martao

1
Her biri için paralel, döngü gövdesinde kodu yürütmek için ayrı dişlerin ayarlandığı anlamına gelir. .NET'in bunu yapmak için etkili bir mekanizması olmasına rağmen, bu önemli bir ek yüktür. Bu nedenle, sadece basit bir işlem yapmanız gerekiyorsa (örneğin bir toplam veya çarpma), paralel foreach daha hızlı olmamalıdır.
Martao

3
@Jignesh bu bile iyi bir ölçüm örneği değil, bu yüzden hiç bahsetmezdim. Kaldır "Thread.Sleep (10);" Her döngü gövdesinden çıkarın ve tekrar deneyin.
stenly

1
@Martao haklıdır, sorun paralel yaklaşımın ardışıktan daha uzun olabileceği nesne kilitleme ek yükleri ile ilgilidir.
stenly

8
@stenly Bence Uyku tam da bunun iyi bir örnek olmasının sebebidir . (Martao'nun açıkladığı gibi) hızlı tekli yinelemelere sahip bir PFE kullanmazsınız - bu nedenle bu cevap yinelemeyi yavaşlatıyor ve PFE'nin (doğru) avantajı vurgulanıyor. Bu sorunun cevapta açıklanması gerektiğine katılıyorum, cesur bir "her zaman daha hızlıdır" çok yanıltıcıdır.
mafu

43
string[] lines = File.ReadAllLines(txtProxyListPath.Text);

// No need for the list
// List<string> list_lines = new List<string>(lines); 

Parallel.ForEach(lines, line =>
{
    //My Stuff
});

Bu, çizgilerin döngü içinde paralel olarak ayrıştırılmasına neden olur. Parallel sınıfına daha ayrıntılı, daha az "referans odaklı" bir giriş yapmak isterseniz, TPL'de Parallel.ForEach ile ilgili bir bölüm içeren bir dizi yazdım .


9

Büyük dosya için aşağıdaki kodu kullanın (daha az belleğe açsınız)

Parallel.ForEach(File.ReadLines(txtProxyListPath.Text), line => {
    //Your stuff
});

2

Bu çizgiler benim için çalıştı.

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(lines , options, (item) =>
{
 //My Stuff
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.