次の方法で共有


方法: 小さいループ本体を高速化する

For() ループの本体が小さい場合、実行速度は同等の順次ループよりも遅くなる場合があります。 データのパーティション分割で発生するオーバーヘッドと、ループの反復ごとにデリゲートを呼び出すことが原因で、パフォーマンスが低下します。 このようなシナリオに対処するために、Partitioner クラスには Create メソッドが用意されています。このメソッドを使用すると、デリゲートの本体で順次ループを実現できます。その結果、デリゲートは 1 回の反復につき 1 回ではなく、1 つのパーティションにつき 1 回のみ呼び出されます。 詳細については、「PLINQ および TPL 用のカスタム パーティショナー」を参照してください。

使用例

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
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);
            }           
        }
    }
}

この例で示す方法は、ループで最小限の処理を実行する場合に役立ちます。 処理の計算負荷が高くなったときは、既定のパーティショナーで For ループまたは ForEach ループを使用することで、同等以上のパフォーマンスが得られる可能性があります。

参照

参照

反復子 (C# プログラミング ガイド)

概念

データの並列化 (タスク並列ライブラリ)

PLINQ および TPL のラムダ式

その他の技術情報

PLINQ および TPL 用のカスタム パーティショナー