Delen via


Procedure: Kleine lusteksten versnellen

Wanneer een Parallel.For lus een kleine hoofdtekst heeft, kan deze langzamer presteren dan de equivalente sequentiële lus, zoals de for-lus in C# en de For-lus in Visual Basic. Tragere prestaties worden veroorzaakt door de overhead die betrokken is bij het partitioneren van de gegevens en de kosten voor het aanroepen van een gemachtigde voor elke lus-iteratie. Om dergelijke scenario's te verhelpen, biedt de Partitioner klasse de Partitioner.Create methode, waarmee u een sequentiële lus kunt opgeven voor de gemachtigdebody, zodat de gemachtigde slechts eenmaal per partitie wordt aangeroepen, in plaats van één keer per iteratie. Zie Aangepaste partities voor PLINQ en TPL voor meer informatie.

Opmerking

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

De methode die in dit voorbeeld wordt gedemonstreerd, is handig wanneer de lus een minimale hoeveelheid werk uitvoert. Naarmate het werk rekenkracht duurder wordt, krijgt u waarschijnlijk dezelfde of betere prestaties door een For of ForEach lus te gebruiken met de standaardpartitiefunctie.

Zie ook