How to: Write a Simple Parallel.ForEach Loop

This example shows how to use a Parallel.ForEach loop to enable data parallelism over any System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T> data source.

Note

This documentation uses lambda expressions to define delegates in PLINQ. If you are not familiar with lambda expressions in C# or Visual Basic, see Lambda Expressions in PLINQ and TPL.

Example

//
// IMPORTANT!!!: Add a reference to System.Drawing.dll
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Drawing;

public class Example
{
    public static void Main()
    {
        // A simple source for demonstration purposes. Modify this path as necessary.
        String[] files = System.IO.Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures", "*.jpg");
        String newDir = @"C:\Users\Public\Pictures\Sample Pictures\Modified";
        System.IO.Directory.CreateDirectory(newDir);

        // Method signature: Parallel.ForEach(IEnumerable<TSource> source, Action<TSource> body)
        // Be sure to add a reference to System.Drawing.dll.
        Parallel.ForEach(files, (currentFile) => 
                                {
                                    // The more computational work you do here, the greater 
                                    // the speedup compared to a sequential foreach loop.
                                    String filename = System.IO.Path.GetFileName(currentFile);
                                    var bitmap = new Bitmap(currentFile);

                                    bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                    bitmap.Save(Path.Combine(newDir, filename));

                                    // Peek behind the scenes to see how work is parallelized.
                                    // But be aware: Thread contention for the Console slows down parallel loops!!!

                                    Console.WriteLine("Processing {0} on thread {1}", filename, Thread.CurrentThread.ManagedThreadId);
                                    //close lambda expression and method invocation
                                });


        // Keep the console window open in debug mode.
        Console.WriteLine("Processing complete. Press any key to exit.");
        Console.ReadKey();
    }
}
' How to: Write a Simple Parallel.ForEach Loop
' IMPORTANT!!!: Add reference to System.Drawing.dll
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Drawing

Module ForEachDemo

    Sub Main()
        ' A simple source for demonstration purposes. Modify this path as necessary.
        Dim files As String() = System.IO.Directory.GetFiles("C:\Users\Public\Pictures\Sample Pictures", "*.jpg")
        Dim newDir As String = "C:\Users\Public\Pictures\Sample Pictures\Modified"
        System.IO.Directory.CreateDirectory(newDir)

        ' Method signature: Parallel.ForEach(IEnumerable<TSource> source, Action<TSource> body)
        ' Be sure to add a reference to System.Drawing.dll.
        Parallel.ForEach(files, Sub(currentFile)
                                    ' The more computational work you do here, the greater 
                                    ' the speedup compared to a sequential foreach loop.
                                    Dim filename As String = System.IO.Path.GetFileName(currentFile)
                                    Dim bitmap As New System.Drawing.Bitmap(currentFile)

                                    bitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone)
                                    bitmap.Save(System.IO.Path.Combine(newDir, filename))

                                    ' Peek behind the scenes to see how work is parallelized.
                                    ' But be aware: Thread contention for the Console slows down parallel loops!!!

                                    Console.WriteLine("Processing {0} on thread {1}", filename, Thread.CurrentThread.ManagedThreadId)
                                    'close lambda expression and method invocation
                                End Sub)


        ' Keep the console window open in debug mode.
        Console.WriteLine("Processing complete. Press any key to exit.")
        Console.ReadKey()
    End Sub
End Module

A ForEach loop works like a For loop. The source collection is partitioned and the work is scheduled on multiple threads based on the system environment. The more processors on the system, the faster the parallel method runs. For some source collections, a sequential loop may be faster, depending on the size of the source, and the kind of work being performed. For more information about performance, see Potential Pitfalls in Data and Task Parallelism

For more information about parallel loops, see How to: Write a Simple Parallel.For Loop.

To use ForEach with a non-generic collection, you can use the Cast extension method to convert the collection to a generic collection, as shown in the following example:

Parallel.ForEach(nonGenericCollection.Cast<object>(),
    currentElement =>
    {
    });
Parallel.ForEach(nonGenericCollection.Cast(Of Object), _
                 Sub(currentElement)
                     ' ... work with currentElement
                 End Sub)

You can also use Parallel LINQ (PLINQ) to parallelize processing of IEnumerable<T> data sources. PLINQ enables you to use declarative query syntax to express the loop behavior. For more information, see Parallel LINQ (PLINQ).

Compiling the Code

  • Copy and paste this code into a Visual Studio 2010 Console Application project.

  • Add a reference to System.Drawing.dll

  • Press F5

See Also

Data Parallelism
Parallel Programming
Parallel LINQ (PLINQ)