Nasıl yapılır: Basit bir Parallel.ForEach döngüsü yazma

Bu örnekte, herhangi bir veya veri Parallel.ForEach kaynağı üzerinde veri paralelliği sağlamak için döngü System.Collections.IEnumerable kullanma hakkında bilgi System.Collections.Generic.IEnumerable<T> verilmektedir.

Not

Bu belge, PLINQ'te temsilci tanımlamak için lambda ifadeleri kullanır. C# veya Visual Basic'daki lambda ifadeleri hakkında bilgi sahibi değilsanız bkz. PLINQ ve TPL'de Lambda ifadeleri.

Örnek

Bu örnekte YOĞUN Parallel.ForEach CPU kullanımına sahip işlemler gösterildi. Örneği çalıştırarak rastgele olarak 2 milyon sayı üretir ve asal sayıları filtrelemeye çalışır. İlk büyük/küçük harf bir döngü aracılığıyla koleksiyon üzerinde for tekrarlar. İkinci büyük/büyük harf aracılığıyla koleksiyon üzerinde Parallel.ForEach tekrarlar. Uygulama tamamlandığında her yinelemenin elde edilen süresi görüntülenir.

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

Döngü Parallel.ForEach bir döngü gibi Parallel.For çalışır. döngüsü kaynak koleksiyonu bölümler ve işi sistem ortamına göre birden çok iş parçacığında zamanlar. Sistemdeki işlemciler ne kadar çoksa paralel yöntem o kadar hızlı çalışır. Bazı kaynak koleksiyonları için, kaynağın boyutuna ve döngü tarafından gerçekleştirdiği iş türüne bağlı olarak sıralı bir döngü daha hızlı olabilir. Performans hakkında daha fazla bilgi için bkz. Verilerde olası tuzaklar ve görev paralelliği.

Paralel döngüler hakkında daha fazla bilgi için bkz. Nasıl: Basit bir Parallel.For döngüsü yazma.

Genel olmayan bir koleksiyon ile kullanmak için, aşağıdaki örnekte gösterildiği gibi, genişletme yöntemini kullanarak koleksiyonu genel Parallel.ForEach Enumerable.Cast bir koleksiyona dönüştürebilirsiniz:

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

Veri kaynaklarının işleme sürecini paralelleştirmek için Paralel LINQ (PLINQ) de IEnumerable<T> kullanabilirsiniz. PLINQ, döngü davranışını ifade etmek için bildirimli sorgu söz dizimi kullanmana olanak sağlar. Daha fazla bilgi için bkz. Paralel LINQ (PLINQ).

Kodu derleme ve çalıştırma

Kodu bir konsol uygulaması olarak veya .NET Core .NET Framework konsol uygulaması olarak derebilirsiniz.

Bu Visual Studio, Visual Basic Desktop ve .NET Core için Windows ve C# konsol uygulaması şablonları vardır.

Komut satırına .NET CLI komutlarını (örneğin, veya ) veya dosyayı oluşturabilir ve bir uygulama için komut satırı derleyicisini dotnet new console dotnet new console -lang vb .NET Framework kullanabilirsiniz.

Komut satırdan bir .NET Core konsol uygulaması çalıştırmak için, dotnet run uygulamanızı içeren klasörden komutunu kullanın.

Konsol uygulamanızı Visual Studio F5 tuşuna basın.

Ayrıca bkz.