【问题标题】:How do I get lazy loading with PLINQ?如何使用 PLINQ 进行延迟加载?
【发布时间】:2013-02-04 04:18:31
【问题描述】:

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 提高应用程序性能的同时获得出色的延迟加载呢?

【问题讨论】:

    标签: c# lazy-loading plinq


    【解决方案1】:

    看看MergeOptions

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 非常好的点... PLINQ 中的缓冲只掩盖了没有延迟加载的问题。也许一种方法是有一个扩展方法来批处理接下来的 n 个项目,并并行执行这些项目,然后返回结果。这可能会产生伪懒惰行为......
      • @tbischel 是的,类似的东西会起作用。另一种选择是使用 BlockingCollectionBoundedCapacity 集。
      猜你喜欢
      • 2011-01-25
      • 1970-01-01
      • 2013-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-30
      相关资源
      最近更新 更多