¿Cómo puedo convertir este código foreach a Parallel.ForEach?


180

Estoy un poco confundido acerca de Parallel.ForEach.
¿Qué es Parallel.ForEachy qué hace exactamente?
No haga referencia a ningún enlace de MSDN.

Aquí hay un ejemplo simple:

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

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

¿Cómo puedo reescribir este ejemplo con Parallel.ForEach?


Esto podría haber sido respondido aquí stackoverflow.com/questions/3789998/…
Ujjwal Manandhar

1
@UjjwalManandhar Eso es bastante diferente, ya que se trata de la diferencia entre la Parallelclase y el uso de PLINQ.
Reed Copsey

18
Otros han respondido cómo puedes reescribir. Entonces ¿Qué es lo que hace? Realiza una "acción" en cada elemento de la colección, al igual que lo normal foreach. La diferencia es que la versión paralela puede hacer muchas "acciones" al mismo tiempo. En la mayoría de los casos (dependiendo de qué computadora está ejecutando el código, y qué tan ocupado está, y otras cosas) será más rápido, y esa es la ventaja más importante. Tenga en cuenta que cuando lo hace en paralelo, no puede saber en qué orden se procesan los artículos. Con un habitual (en serie) foreach, tiene la garantía de que lines[0]es lo primero, luego lines[1], y así sucesivamente.
Jeppe Stig Nielsen

1
Será @JeppeStigNielsen no siempre será más rápido ya que hay una sobrecarga significativa con hacer cosas paralelas. Depende del tamaño de la colección en la que está iterando y de la acción dentro. Lo correcto es medir la diferencia entre usar Parallel.ForEach () y usar foreach (). Muchas veces un foreach normal () es más rápido.
Dave Black

3
@DaveBlack Claro. Tendrá que medir si es más rápido o más lento, en cada caso. Solo estaba tratando de describir la paralelización en general.
Jeppe Stig Nielsen

Respuestas:


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

66
Solo quería señalarlo (más para el OP) para que no hubiera un pensamiento equivocado de que solo funciona List<T>;)
Reed Copsey

1
Gracias por la atención y respuesta. Utilicé List <string> en mis códigos debido a la eliminación de elementos duplicados mediante listas HASH. con una matriz regular no podemos eliminar duplicados fácilmente :).
SilverLight

119
Estoy confundido que esta respuesta se marca como la respuesta correcta, ya que no hay una explicación a la pregunta original, mensajes ... "¿Cuál es Parallel.ForEach y lo que exactamente hacer?"
FOSE

66
@fosb El problema es que el título de la pregunta fue editado para cambiar completamente el significado ... por lo que esta respuesta ya no tiene ningún sentido. Habiendo dicho eso, sigue siendo una respuesta pobre
aw04

274

Bucle Foreach:

  • Las iteraciones tienen lugar secuencialmente, una por una.
  • El bucle foreach se ejecuta desde un único subproceso.
  • foreach loop se define en cada framework de .NET
  • La ejecución de procesos lentos puede ser más lenta , ya que se ejecutan en serie
    • El proceso 2 no puede comenzar hasta que se complete 1. El proceso 3 no puede comenzar hasta que 2 y 1 hayan terminado ...
  • La ejecución de procesos rápidos puede ser más rápida , ya que no hay gastos generales de subprocesos

Paralelo para cada uno:

  • La ejecución tiene lugar de forma paralela.
  • Parallel.ForEach usa múltiples hilos.
  • Parallel.ForEach se define en los marcos .Net 4.0 y superiores.
  • La ejecución de procesos lentos puede ser más rápida , ya que pueden ejecutarse en paralelo
    • Los procesos 1, 2 y 3 pueden ejecutarse simultáneamente (ver subprocesos reutilizados en el ejemplo, a continuación)
  • La ejecución de procesos rápidos puede ser más lenta , debido a la sobrecarga de subprocesos adicionales

El siguiente ejemplo demuestra claramente la diferencia entre el bucle foreach tradicional y

Parallel.ForEach () Ejemplo

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

Salida

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 ejemplo

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
Realmente no estoy de acuerdo con su 'reclamo' de que Parallel.ForEach es (siempre) más rápido. Esto realmente depende del peso de la operación dentro del bucle. Esto puede o no valer la sobrecarga de introducir el paralelismo.
Martao

1
Bueno, el paralelo para cada uno significa que se configuran hilos separados para ejecutar el código en el cuerpo del bucle. Aunque .NET tiene un mecanismo eficiente para hacer esto, esta es una sobrecarga considerable. Entonces, si solo tiene que realizar una operación simple (por ejemplo, una suma o multiplicación), el foreach paralelo no debería ser más rápido.
Martao

3
@Jignesh, este ni siquiera es un buen ejemplo de medición, así que no me referiría a esto en absoluto. Eliminar "Thread.Sleep (10);" de cada cuerpo de bucle e inténtalo de nuevo.
stenly

1
@Martao tiene razón, el problema es con los gastos generales de bloqueo de objetos donde el enfoque paralelo podría ser más largo que secuencial.
stenly

8
@Stenly creo que el sueño es precisamente la razón por la cual es un buen ejemplo. No usaría un PFE con iteraciones simples rápidas (como explicó Martao), por lo que esta respuesta está haciendo que la iteración sea lenta y se resalta la ventaja (correcta) del PFE. Aunque estoy de acuerdo en que esto debe explicarse en la respuesta, un negrita "siempre es más rápido" es muy engañoso.
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
});

Esto hará que las líneas se analicen en paralelo, dentro del bucle. Si desea una introducción más detallada y menos "orientada a la referencia" a la clase Paralelo, escribí una serie sobre el TPL que incluye una sección sobre Parallel.ForEach .


9

Para archivos grandes, use el siguiente código (tiene menos memoria)

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

2

Estas líneas me funcionaron.

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(lines , options, (item) =>
{
 //My Stuff
});
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.