如何使用PLINQ进行延迟加载?

时间:2013-02-04 04:18:31

标签: c# lazy-loading plinq

关于linq的好处之一是根据请求懒惰处理无限数据源。我尝试并行化我的查询,发现延迟加载不起作用。例如......

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提高应用程序性能的同时,如何获得漂亮的延迟加载?

2 个答案:

答案 0 :(得分:5)

查看MergeOptions

 var next = source.AsParallel()
              .WithMergeOptions(ParallelMergeOptions.NotBuffered)
              .Select(i => ExpensiveCall(i));

答案 1 :(得分:3)

我认为你混淆了两件不同的事情。这里的问题不是延迟加载(即只加载必要的加载),这里的问题是输出缓冲(即不立即返回结果)。

在你的情况下,你最终会得到你的结果,虽然它可能需要一段时间(对我来说,它需要500个结果才能返回第一批)。缓冲是出于性能原因而完成的,但在您的情况下,这是没有意义的。正如Ian正确指出的那样,你应该使用.WithMergeOptions(ParallelMergeOptions.NotBuffered)来禁用输出缓冲。

但是,据我所知,PLINQ不会进行延迟加载,也无法改变它。这意味着如果您的消费者(在您的情况下,foreach循环)太慢,PLINQ将生成比必要更快的结果,并且仅在您完成迭代结果时才会停止。这意味着PLINQ会浪费CPU时间和内存。