Dela via


Gör så här: Snabba upp små loopkroppar

När en Parallel.For loop har en liten brödtext kan den utföras långsammare än motsvarande sekventiella loop, till exempel for-loopen i C# och For-loopen i Visual Basic. Långsammare prestanda orsakas av omkostnaderna för partitionering av data och kostnaden för att anropa ett ombud för varje loop-iteration. För att hantera sådana scenarier Partitioner tillhandahåller Partitioner.Create klassen metoden, som gör att du kan ange en sekventiell loop för ombudstexten, så att ombudet endast anropas en gång per partition, i stället för en gång per iteration. Mer information finns i Anpassade partitionerare för PLINQ och TPL.

Exempel

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {

        // Source must be array or IList.
        var source = Enumerable.Range(0, 100000).ToArray();

        // Partition the entire source array.
        var rangePartitioner = Partitioner.Create(0, source.Length);

        double[] results = new double[source.Length];

        // Loop over the partitions in parallel.
        Parallel.ForEach(rangePartitioner, (range, loopState) =>
        {
            // Loop over each range element without a delegate invocation.
            for (int i = range.Item1; i < range.Item2; i++)
            {
                results[i] = source[i] * Math.PI;
            }
        });

        Console.WriteLine("Operation complete. Print results? y/n");
        char input = Console.ReadKey().KeyChar;
        if (input == 'y' || input == 'Y')
        {
            foreach(double d in results)
            {
                Console.Write("{0} ", d);
            }
        }
    }
}
Imports System.Threading.Tasks
Imports System.Collections.Concurrent

Module PartitionDemo

    Sub Main()
        ' Source must be array or IList.
        Dim source = Enumerable.Range(0, 100000).ToArray()

        ' Partition the entire source array. 
        ' Let the partitioner size the ranges.
        Dim rangePartitioner = Partitioner.Create(0, source.Length)

        Dim results(source.Length - 1) As Double

        ' Loop over the partitions in parallel. The Sub is invoked
        ' once per partition.
        Parallel.ForEach(rangePartitioner, Sub(range, loopState)

                                               ' Loop over each range element without a delegate invocation.
                                               For i As Integer = range.Item1 To range.Item2 - 1
                                                   results(i) = source(i) * Math.PI
                                               Next
                                           End Sub)
        Console.WriteLine("Operation complete. Print results? y/n")
        Dim input As Char = Console.ReadKey().KeyChar
        If input = "y"c Or input = "Y"c Then
            For Each d As Double In results
                Console.Write("{0} ", d)
            Next
        End If

    End Sub
End Module

Metoden som visas i det här exemplet är användbar när loopen utför en minimal mängd arbete. Eftersom arbetet blir mer beräkningsmässigt dyrt får du förmodligen samma eller bättre prestanda med hjälp av en For eller ForEach -loop med standardpartitioneraren.

Se även