Útmutató: Egyszerű Parallel.ForEach-ciklus írása
Ez a cikk bemutatja, hogyan lehet hurok használatával Parallel.ForEach engedélyezni az adatok párhuzamosságát bármely System.Collections.IEnumerable vagy System.Collections.Generic.IEnumerable<T> adatforráson keresztül.
Feljegyzés
Ez a dokumentáció lambdakifejezésekkel definiálja a meghatalmazottakat a PLINQ-ban. Ha nem ismeri a lambda kifejezéseket a C# vagy a Visual Basic alkalmazásban, tekintse meg a Lambda-kifejezéseket a PLINQ-ban és a TPL-ben.
Példa
Ez a példa a cpu-igényes Parallel.ForEach műveletekre mutat be. A példa futtatásakor véletlenszerűen generál 2 millió számot, és megpróbál prímszámokra szűrni. Az első eset cikluson keresztül viszi át a gyűjteményt for
. A második eset a gyűjteményen keresztül Parallel.ForEachiterál. Az alkalmazás befejezésekor az egyes iterációk által kapott idő jelenik meg.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace ParallelExample
{
class Program
{
static void Main()
{
// 2 million
var limit = 2_000_000;
var numbers = Enumerable.Range(0, limit).ToList();
var watch = Stopwatch.StartNew();
var primeNumbersFromForeach = GetPrimeList(numbers);
watch.Stop();
var watchForParallel = Stopwatch.StartNew();
var primeNumbersFromParallelForeach = GetPrimeListWithParallel(numbers);
watchForParallel.Stop();
Console.WriteLine($"Classical foreach loop | Total prime numbers : {primeNumbersFromForeach.Count} | Time Taken : {watch.ElapsedMilliseconds} ms.");
Console.WriteLine($"Parallel.ForEach loop | Total prime numbers : {primeNumbersFromParallelForeach.Count} | Time Taken : {watchForParallel.ElapsedMilliseconds} ms.");
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
/// <summary>
/// GetPrimeList returns Prime numbers by using sequential ForEach
/// </summary>
/// <param name="inputs"></param>
/// <returns></returns>
private static IList<int> GetPrimeList(IList<int> numbers) => numbers.Where(IsPrime).ToList();
/// <summary>
/// GetPrimeListWithParallel returns Prime numbers by using Parallel.ForEach
/// </summary>
/// <param name="numbers"></param>
/// <returns></returns>
private static IList<int> GetPrimeListWithParallel(IList<int> numbers)
{
var primeNumbers = new ConcurrentBag<int>();
Parallel.ForEach(numbers, number =>
{
if (IsPrime(number))
{
primeNumbers.Add(number);
}
});
return primeNumbers.ToList();
}
/// <summary>
/// IsPrime returns true if number is Prime, else false.(https://en.wikipedia.org/wiki/Prime_number)
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
private static bool IsPrime(int number)
{
if (number < 2)
{
return false;
}
for (var divisor = 2; divisor <= Math.Sqrt(number); divisor++)
{
if (number % divisor == 0)
{
return false;
}
}
return true;
}
}
}
Imports System.Collections.Concurrent
Namespace ParallelExample
Class Program
Shared Sub Main()
' 2 million
Dim limit = 2_000_000
Dim numbers = Enumerable.Range(0, limit).ToList()
Dim watch = Stopwatch.StartNew()
Dim primeNumbersFromForeach = GetPrimeList(numbers)
watch.Stop()
Dim watchForParallel = Stopwatch.StartNew()
Dim primeNumbersFromParallelForeach = GetPrimeListWithParallel(numbers)
watchForParallel.Stop()
Console.WriteLine($"Classical foreach loop | Total prime numbers : {primeNumbersFromForeach.Count} | Time Taken : {watch.ElapsedMilliseconds} ms.")
Console.WriteLine($"Parallel.ForEach loop | Total prime numbers : {primeNumbersFromParallelForeach.Count} | Time Taken : {watchForParallel.ElapsedMilliseconds} ms.")
Console.WriteLine("Press any key to exit.")
Console.ReadLine()
End Sub
' GetPrimeList returns Prime numbers by using sequential ForEach
Private Shared Function GetPrimeList(numbers As IList(Of Integer)) As IList(Of Integer)
Return numbers.Where(AddressOf IsPrime).ToList()
End Function
' GetPrimeListWithParallel returns Prime numbers by using Parallel.ForEach
Private Shared Function GetPrimeListWithParallel(numbers As IList(Of Integer)) As IList(Of Integer)
Dim primeNumbers = New ConcurrentBag(Of Integer)()
Parallel.ForEach(numbers, Sub(number)
If IsPrime(number) Then
primeNumbers.Add(number)
End If
End Sub)
Return primeNumbers.ToList()
End Function
' IsPrime returns true if number is Prime, else false.(https://en.wikipedia.org/wiki/Prime_number)
Private Shared Function IsPrime(number As Integer) As Boolean
If number < 2 Then
Return False
End If
For divisor = 2 To Math.Sqrt(number)
If number Mod divisor = 0 Then
Return False
End If
Next
Return True
End Function
End Class
End Namespace
A Parallel.ForEach hurok úgy működik, mint egy Parallel.For hurok. A hurok particionálja a forrásgyűjteményt, és a rendszerkörnyezet alapján több szálon ütemezi a munkát. Minél több processzor van a rendszeren, annál gyorsabban fut a párhuzamos metódus. Egyes forrásgyűjtemények esetében a szekvenciális hurok gyorsabb lehet a forrás méretétől és a ciklus által végzett munka típusától függően. A teljesítménnyel kapcsolatos további információkért lásd az adatok és a tevékenységek párhuzamosságának lehetséges buktatóit.
A párhuzamos hurkokkal kapcsolatos további információkért lásd : How to: Write a simple Parallel.For loop.
Ha a Parallel.ForEach hurkot nem általános gyűjteményrel szeretné használni, a Enumerable.Cast bővítménymetódussal átalakíthatja a gyűjteményt általános gyűjteménysé, ahogyan az alábbi példában látható:
Parallel.ForEach(nonGenericCollection.Cast<object>(),
currentElement =>
{
});
Parallel.ForEach(nonGenericCollection.Cast(Of Object), _
Sub(currentElement)
' ... work with currentElement
End Sub)
A Párhuzamos LINQ (PLINQ) használatával párhuzamossá teheti az adatforrások feldolgozását IEnumerable<T> . A PLINQ lehetővé teszi deklaratív lekérdezési szintaxis használatát a ciklus viselkedésének kifejezéséhez. További információ: Parallel LINQ (PLINQ).
A kód fordítása és futtatása
A kódot .NET-keretrendszer konzolalkalmazásként vagy .NET Core-konzolalkalmazásként fordíthatja le.
A Visual Studióban Visual Basic és C# konzolalkalmazássablonok találhatók a Windows Desktophoz és a .NET Core-hoz.
A parancssorból használhatja a .NET CLI-parancsokat (például) vagy dotnet new console -lang vb
létrehozhatja a fájlt, dotnet new console
és használhatja a parancssori fordítót egy .NET-keretrendszer-alkalmazáshoz.
Ha .NET Core-konzolalkalmazást szeretne futtatni a parancssorból, használja dotnet run
az alkalmazást tartalmazó mappából.
A konzolalkalmazás Visual Studióból való futtatásához nyomja le az F5 billentyűt.
Lásd még
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: