5

linq の優れた点の 1 つは、無限のデータ ソースが要求に応じて遅延処理されることです。クエリの並列化を試みたところ、遅延読み込みが機能していないことがわかりました。例えば...

class Program
{
    static void Main(string[] args)
    {
        var source = Generator();
        var next = source.AsParallel().Select(i => ExpensiveCall(i));
        foreach (var i in next)
        {
            System.Console.WriteLine(i);
        }
    }

    public static IEnumerable<int> Generator()
    {
        int i = 0;
        while (true)
        {
            yield return i;
            i++;
        }
    }

    public static int ExpensiveCall(int arg)
    {
        System.Threading.Thread.Sleep(5000);
        return arg*arg;
    }
}

このプログラムは結果を生成できません。これはおそらく、各ステップで、ジェネレーターへのすべての呼び出しが枯渇するのを待っているためです。「AsParallel」呼び出しを実行すると、問題なく動作します。では、PLINQ を使用してアプリケーションのパフォーマンスを向上させながら、適切な遅延読み込みを取得するにはどうすればよいでしょうか?

4

2 に答える 2

5

MergeOptionsを見てください。

 var next = source.AsParallel()
              .WithMergeOptions(ParallelMergeOptions.NotBuffered)
              .Select(i => ExpensiveCall(i));
于 2013-02-04T04:28:44.013 に答える
3

あなたは2つの異なることを混同していると思います。ここでの問題は、遅延ロード (つまり、必要な分だけロードする) ではなく、出力バッファリング (つまり、すぐに結果を返さない) です。

あなたの場合、結果は最終的に得られますが、しばらく時間がかかる場合があります (私にとっては、最初のバッチを返すには 500 のような結果が必要です)。バッファリングはパフォーマンス上の理由から行われますが、あなたの場合、それは意味がありません。Ian が正しく指摘したように、.WithMergeOptions(ParallelMergeOptions.NotBuffered)出力バッファリングを無効にするために使用する必要があります。

しかし、私の知る限り、PLINQ は遅延読み込みを行わず、それを変更する方法はありません。つまり、コンシューマー (この場合はforeachループ) が遅すぎる場合、PLINQ は必要以上に速く結果を生成し、結果の反復が終了したときにのみ停止します。これは、PLINQ が CPU 時間とメモリを浪費している可能性があることを意味します。

于 2013-02-04T12:59:18.127 に答える