Практическое руководство. Написание пользовательской агрегатной функции PLINQHow to: Write a Custom PLINQ Aggregate Function

Этот пример демонстрирует, как использовать метод Aggregate для применения пользовательской функции агрегирования к исходной последовательности.This example shows how to use the Aggregate method to apply a custom aggregation function to a source sequence.

Предупреждение

Этот пример предназначен для демонстрации использования и может выполняться не быстрее аналогичного последовательного запроса LINQ to Objects.This example is intended to demonstrate usage, and might not run faster than the equivalent sequential LINQ to Objects query. См. дополнительные сведения об ускорении выполнения в PLINQ.For more information about speedup, see Understanding Speedup in PLINQ.

ПримерExample

Следующий пример вычисляет стандартное отклонение для последовательности целых чисел.The following example calculates the standard deviation of a sequence of integers.

namespace PLINQAggregation
{
    using System;
    using System.Linq;

    class aggregation
    {
        static void Main(string[] args)
        {

            // Create a data source for demonstration purposes.
            int[] source = new int[100000];
            Random rand = new Random();
            for (int x = 0; x < source.Length; x++)
            {
                // Should result in a mean of approximately 15.0.
                source[x] = rand.Next(10, 20);
            }

            // Standard deviation calculation requires that we first
            // calculate the mean average. Average is a predefined
            // aggregation operator, along with Max, Min and Count.
            double mean = source.AsParallel().Average();


            // We use the overload that is unique to ParallelEnumerable. The 
            // third Func parameter combines the results from each thread.
            double standardDev = source.AsParallel().Aggregate(
                // initialize subtotal. Use decimal point to tell 
                // the compiler this is a type double. Can also use: 0d.
                0.0,

                // do this on each thread
                 (subtotal, item) => subtotal + Math.Pow((item - mean), 2),

                 // aggregate results after all threads are done.
                 (total, thisThread) => total + thisThread,

                // perform standard deviation calc on the aggregated result.
                (finalSum) => Math.Sqrt((finalSum / (source.Length - 1)))
            );
            Console.WriteLine("Mean value is = {0}", mean);
            Console.WriteLine("Standard deviation is {0}", standardDev);
            Console.ReadLine();

        }
    }
}
Class aggregation
    Private Shared Sub Main(ByVal args As String())

        ' Create a data source for demonstration purposes.
        Dim source As Integer() = New Integer(99999) {}
        Dim rand As New Random()
        For x As Integer = 0 To source.Length - 1
            ' Should result in a mean of approximately 15.0.
            source(x) = rand.[Next](10, 20)
        Next

        ' Standard deviation calculation requires that we first
        ' calculate the mean average. Average is a predefined
        ' aggregation operator, along with Max, Min and Count.
        Dim mean As Double = source.AsParallel().Average()


        ' We use the overload that is unique to ParallelEnumerable. The 
        ' third Func parameter combines the results from each thread.
        ' initialize subtotal. Use decimal point to tell 
        ' the compiler this is a type double. Can also use: 0d.

        ' do this on each thread

        ' aggregate results after all threads are done.

        ' perform standard deviation calc on the aggregated result.
        Dim standardDev As Double = source.AsParallel().Aggregate(0.0R, Function(subtotal, item) subtotal + Math.Pow((item - mean), 2), Function(total, thisThread) total + thisThread, Function(finalSum) Math.Sqrt((finalSum / (source.Length - 1))))
        Console.WriteLine("Mean value is = {0}", mean)
        Console.WriteLine("Standard deviation is {0}", standardDev)

        Console.ReadLine()
    End Sub
End Class

В этом примере используется перегрузка стандартного оператора запроса Aggregate, уникального для PLINQ.This example uses an overload of the Aggregate standard query operator that is unique to PLINQ. Эта перегрузка принимает дополнительный System.Func<T1,T2,TResult> в качестве третьего входного параметра.This overload takes an extra System.Func<T1,T2,TResult> as the third input parameter. Этот делегат объединяет результаты из всех потоков и выполняет окончательный расчет на основе объединенных результатов.This delegate combines the results from all threads before it performs the final calculation on the aggregated results. В этом примере он складывает суммы из всех потоков.In this example we add together the sums from all the threads.

Если тело лямбда-выражения состоит из одного выражения, то возвращаемое значение делегата System.Func<T,TResult> принимает значение этого выражения.Note that when a lambda expression body consists of a single expression, the return value of the System.Func<T,TResult> delegate is the value of the expression.

См. такжеSee also