Come posso convertire questo codice foreach in Parallel.ForEach?


180

Sono un po 'confuso Parallel.ForEach.
Che cos'è Parallel.ForEache cosa fa esattamente?
Si prega di non fare riferimento a nessun collegamento MSDN.

Ecco un semplice esempio:

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

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

Come posso riscrivere questo esempio con Parallel.ForEach?


Questo potrebbe essere stato risposto qui stackoverflow.com/questions/3789998/...
Ujjwal Manandhar

1
@UjjwalManandhar In realtà è abbastanza diverso, in quanto si chiede la differenza tra la Parallelclasse e l'utilizzo di PLINQ.
Reed Copsey,

18
Altri hanno risposto come puoi riscrivere. Quindi, cosa fa? Esegue "un'azione" su ogni elemento della raccolta, proprio come un normale foreach. La differenza è che la versione parallela può fare molte "azioni" contemporaneamente. Nella maggior parte dei casi (a seconda del computer su cui è in esecuzione il codice, della sua disponibilità e di altre cose) sarà più veloce e questo è il vantaggio più importante. Nota che quando lo fai in parallelo, non puoi sapere in quale ordine vengono elaborati gli articoli. Con un normale (seriale) foreach, sei sicuro che lines[0]viene prima, poi lines[1]e così via.
Jeppe Stig Nielsen,

1
@JeppeStigNielsen Sarà Non sempre essere più veloce in quanto v'è grande carico di lavoro con fare le cose in parallelo. Dipende dalle dimensioni della raccolta su cui stai ripetendo e dall'azione all'interno. La cosa corretta da fare è misurare effettivamente la differenza tra l'utilizzo di Parallel.ForEach () e l'uso di foreach (). Molte volte un foreach normale () è più veloce.
Dave Black

3
@DaveBlack Certo. Si dovrà misurare se è più veloce o più lento, in ogni caso. Stavo solo cercando di descrivere la parallelizzazione in generale.
Jeppe Stig Nielsen,

Risposte:


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

6
Volevo solo segnalarlo (più per l'OP) in modo che non ci fosse un pensiero fuorviato che funziona solo List<T>;)
Reed Copsey

1
grazie per l'attenzione e la risposta. ho usato List <string> nei miei codici a causa della rimozione di elementi duplicati usando gli elenchi HASH. con array regolari non possiamo rimuovere facilmente i duplicati :).
SilverLight,

119
Sono confuso che questa risposta sia contrassegnata come la risposta giusta, poiché non vi è alcuna spiegazione alla domanda originale sui post "Cos'è Parallel.For Ognuno e cosa fa esattamente?" ...
fose

6
@fosb Il problema è che il titolo della domanda è stato modificato per cambiare completamente il significato ... quindi questa risposta non ha più senso. Detto questo, è ancora una cattiva risposta
aw04

274

Foreach loop:

  • Le iterazioni si svolgono in sequenza, una per una
  • il ciclo foreach viene eseguito da un singolo thread.
  • foreach loop è definito in ogni framework di .NET
  • L'esecuzione di processi lenti può essere più lenta , poiché vengono eseguiti in serie
    • Il processo 2 non può iniziare fino al termine di 1. Il processo 3 non può iniziare fino al completamento di 2 e 1 ...
  • L'esecuzione di processi rapidi può essere più veloce , poiché non vi è alcun overhead di threading

Parallel.ForEach:

  • L'esecuzione avviene in modo parallelo.
  • Parallel.ForEach utilizza più thread.
  • Parallel.ForEach è definito in framework .Net 4.0 e versioni successive.
  • L'esecuzione di processi lenti può essere più veloce , poiché possono essere eseguiti in parallelo
    • I processi 1, 2 e 3 possono essere eseguiti contemporaneamente (vedere i thread riutilizzati nell'esempio di seguito)
  • L'esecuzione di processi rapidi può essere più lenta , a causa dell'overhead di threading aggiuntivo

L'esempio seguente dimostra chiaramente la differenza tra il ciclo foreach tradizionale e

Esempio di Parallel.ForEach ()

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();
        }
    }
}

Produzione

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

Usando Parallel.ForEach esempio

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
Non sono davvero d'accordo con la tua "affermazione" che Parallel.ForEach è (sempre) più veloce. Questo dipende davvero dalla pesantezza dell'operazione all'interno del loop. Questo può o meno valere il sovraccarico dell'introduzione del paralellismo.
Martao,

1
Bene, il parallelo per ciascuno significa che sono impostati thread separati per eseguire il codice nel corpo del loop. Anche se .NET ha un meccanismo efficiente per farlo, questo è un notevole sovraccarico. Quindi, se devi semplicemente eseguire un'operazione (ad es. Una somma o una moltiplicazione), la foreach parallela non dovrebbe essere più veloce.
Martao,

3
@Jignesh questo non è nemmeno un buon esempio di misurazione, quindi non vorrei fare riferimento a questo. Rimuovi "Thread.Sleep (10);" da ciascun corpo del loop e riprovare.
severamente il

1
@Martao ha ragione, il problema è con le spese generali di blocco degli oggetti in cui l'approccio parallelo potrebbe essere più lungo del sequenziale.
severamente il

8
@stremamente penso che il sonno sia proprio il motivo per cui è un buon esempio. Non useresti un PFE con iterazioni singole veloci (come ha spiegato Martao) - quindi questa risposta sta rallentando l'iterazione e il vantaggio (corretto) di PFE è evidenziato. Concordo però che ciò debba essere spiegato nella risposta, un grassetto "è sempre più veloce" è molto fuorviante.
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
});

Questo farà sì che le linee vengano analizzate in parallelo, all'interno del loop. Se vuoi un'introduzione più dettagliata, meno "orientata al riferimento" alla classe Parallel, ho scritto una serie sul TPL che include una sezione su Parallel.ForEach .


9

Per file di grandi dimensioni, utilizzare il codice seguente (si ha meno memoria)

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

2

Queste linee hanno funzionato per me.

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(lines , options, (item) =>
{
 //My Stuff
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.