Практическое руководство. Написание простого цикла Parallel.ForEach
В этом примере показано, как использовать цикл Parallel.ForEach, чтобы включить параллелизм данных для любого источника данных System.Collections.IEnumerable или System.Collections.Generic.IEnumerable<T>.
![]() |
---|
В этой документации для определения делегатов в PLINQ используются лямбда-выражения.Сведения о лямбда-выражениях в C# или Visual Basic см. в разделе Лямбда-выражения в PLINQ и библиотеке параллельных задач. |
Пример
' 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
namespace ForEachDemo
{
using System;
using System.Drawing; // requires system.Drawing.dll
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class SimpleForEach
{
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)
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);
System.Drawing.Bitmap bitmap = 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
); //close method invocation
// Keep the console window open in debug mode.
Console.WriteLine("Processing complete. Press any key to exit.");
Console.ReadKey();
}
}
}
Цикл ForEach работает как цикл For. Исходная коллекция разделяется, и работа планируется для нескольких потоков в зависимости от системной среды. Чем больше процессоров в системе, тем быстрее выполняется параллельный метод. В случае некоторых исходных коллекций последовательный цикл может выполняться быстрее в зависимости от размера источника и типа выполняемых работ. Дополнительные сведения о производительности см. в разделе Потенциальные ошибки, связанные с параллелизмом данных и задач.
Дополнительные сведения о параллельных циклах см. в разделе Практическое руководство. Написание простого цикла Parallel.For.
Чтобы использовать ForEach с неуниверсальной коллекцией, можно воспользоваться методом расширения Cast<TResult> для преобразования коллекции в универсальную, как показано в следующем примере.
Parallel.ForEach(nonGenericCollection.Cast(Of Object), _
Sub(currentElement)
' ... work with currentElement
End Sub)
Parallel.ForEach(nonGenericCollection.Cast<object>(),
currentElement =>
{
});
Также можно использовать параллельный LINQ (PLINQ) для параллельной обработки источников данных IEnumerable<T>. PLINQ позволяет использовать декларативный синтаксис запроса для выражения поведения цикла. Дополнительные сведения см. в разделе Parallel LINQ (PLINQ).
Компиляция кода
Скопируйте и вставьте этот код в проект консольного приложения Visual Studio 2010.
Добавьте ссылку на System.Drawing.dll.
Нажмите F5.
См. также
Основные понятия
Параллелизм данных (библиотека параллельных задач)