Procedura: Scrivere un ciclo Parallel.ForEach sempliceHow to: Write a simple Parallel.ForEach loop

Questo esempio mostra come usare un ciclo Parallel.ForEach per abilitare il parallelismo dei dati in un'origine dati System.Collections.IEnumerable o System.Collections.Generic.IEnumerable<T>.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.

Nota

Le espressioni lambda sono usate nella documentazione per definire i delegati in PLINQ.This documentation uses lambda expressions to define delegates in PLINQ. Se non si ha familiarità con le espressioni lambda in C# o Visual Basic, vedere Espressioni lambda in PLINQ e TPL.If you are not familiar with lambda expressions in C# or Visual Basic, see Lambda expressions in PLINQ and TPL.

EsempioExample

Questo esempio presuppone che diversi file con estensione jpg siano presenti in una cartella C:\Users\Public\Pictures\Sample Pictures e crea una nuova sottocartella con nome Modified.This example assumes you have several .jpg files in a C:\Users\Public\Pictures\Sample Pictures folder and creates a new sub-folder named Modified. Quando si esegue l'esempio, il codice ruota ogni immagine con estensione jpg in Sample Pictures e la salva in Modified.When you run the example, it rotates each .jpg image in Sample Pictures and saves it to Modified. È possibile modificare i due percorsi in base alle esigenze.You can modify the two paths as necessary.

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 = Directory.GetFiles(@"C:\Users\Public\Pictures\Sample Pictures", "*.jpg");
        string newDir = @"C:\Users\Public\Pictures\Sample Pictures\Modified";
        Directory.CreateDirectory(newDir);

        // Method signature: Parallel.ForEach(IEnumerable<TSource> source, Action<TSource> body)
        Parallel.ForEach(files, (currentFile) => 
                                {
                                    // The more computational work you do here, the greater 
                                    // the speedup compared to a sequential foreach loop.
                                    string filename = 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 {filename} on thread {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();
    }
}
Imports System.IO
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() = Directory.GetFiles("C:\Users\Public\Pictures\Sample Pictures", "*.jpg")
        Dim newDir As String = "C:\Users\Public\Pictures\Sample Pictures\Modified"
        Directory.CreateDirectory(newDir)
       
        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 = Path.GetFileName(currentFile)
                                    Dim bitmap As New Bitmap(currentFile)

                                    bitmap.RotateFlip(System.Drawing.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 {filename} on thread {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

Un ciclo Parallel.ForEach funziona come un ciclo Parallel.For.A Parallel.ForEach loop works like a Parallel.For loop. Il ciclo esegue il partizionamento della raccolta di origine e pianifica il lavoro in più thread in base all'ambiente di sistema.The loop partitions the source collection and schedules the work on multiple threads based on the system environment. Più processori ci sono nel sistema, più velocemente viene eseguito il metodo parallelo.The more processors on the system, the faster the parallel method runs. Per alcune raccolte di origine può risultare più veloce un ciclo sequenziale, a seconda delle dimensioni dell'origine e del tipo di attività svolta dal ciclo.For some source collections, a sequential loop may be faster, depending on the size of the source and the kind of work the loop performs. Per ulteriori informazioni sulle prestazioni, vedere potenziali trappole nel parallelismo di dati e attività.For more information about performance, see Potential pitfalls in data and task parallelism.

Per altre informazioni sui cicli paralleli, vedere Procedura: Scrivere un ciclo Parallel.For semplice.For more information about parallel loops, see How to: Write a simple Parallel.For loop.

Per usare Parallel.ForEach con una raccolta non generica, è possibile usare il metodo di estensione Enumerable.Cast per convertire la raccolta in una generica, come illustrato nell'esempio seguente:To use Parallel.ForEach with a non-generic collection, you can use the Enumerable.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)

È anche possibile usare Parallel LINQ (PLINQ) per parallelizzare l'elaborazione di origini dati IEnumerable<T>.You can also use Parallel LINQ (PLINQ) to parallelize processing of IEnumerable<T> data sources. PLINQ consente di usare la sintassi di query dichiarativa per esprimere il comportamento di ciclo.PLINQ enables you to use declarative query syntax to express the loop behavior. Per altre informazioni, vedere Parallel LINQ (PLINQ).For more information, see Parallel LINQ (PLINQ).

Compilare ed eseguire il codiceCompile and run the code

È possibile compilare il codice come applicazione console per .NET Framework o come applicazione console per .NET Core.You can compile the code as a console application for .NET Framework or as a console application for .NET Core.

In Visual Studio esistono modelli di applicazione console Visual Basic e C# per Windows Desktop e .NET Core.In Visual Studio, there are Visual Basic and C# console application templates for Windows Desktop and .NET Core.

Dalla riga di comando è possibile usare .NET Core e gli strumenti CLI corrispondenti (ad esempio dotnet new console o dotnet new console -lang vb) oppure creare il file e usare il compilatore della riga di comando per un'applicazione .NET Framework.From the command line, you can use either .NET Core and its CLI tools (for example, dotnet new console or dotnet new console -lang vb), or you can create the file and use the command-line compiler for a .NET Framework application.

Per un progetto .NET Core è necessario fare riferimento al pacchetto NuGet System.Drawing.Common.For a .NET Core project, you must reference the System.Drawing.Common NuGet package. In Visual Studio usare Gestione pacchetti NuGet per installare il pacchetto.In Visual Studio, use the NuGet Package Manager to install the package. In alternativa, è possibile aggiungere un riferimento al pacchetto nel file con estensione *.csproj o *.vbproj:Alternatively, you can add a reference to the package in your *.csproj or *.vbproj file:

<ItemGroup>
     <PackageReference Include="System.Drawing.Common" Version="4.5.1" />
</ItemGroup>

Per eseguire un'applicazione console .NET Core dalla riga di comando, usare dotnet run dalla cartella che contiene l'applicazione.To run a .NET Core console application from the command line, use dotnet run from the folder that contains your application.

Per eseguire l'applicazione console da Visual Studio, premere F5.To run your console application from Visual Studio, press F5.

Vedere ancheSee also