关于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提高应用程序性能的同时,如何获得漂亮的延迟加载?
答案 0 :(得分:5)
var next = source.AsParallel()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
.Select(i => ExpensiveCall(i));
答案 1 :(得分:3)
我认为你混淆了两件不同的事情。这里的问题不是延迟加载(即只加载必要的加载),这里的问题是输出缓冲(即不立即返回结果)。
在你的情况下,你最终会得到你的结果,虽然它可能需要一段时间(对我来说,它需要500个结果才能返回第一批)。缓冲是出于性能原因而完成的,但在您的情况下,这是没有意义的。正如Ian正确指出的那样,你应该使用.WithMergeOptions(ParallelMergeOptions.NotBuffered)
来禁用输出缓冲。
但是,据我所知,PLINQ不会进行延迟加载,也无法改变它。这意味着如果您的消费者(在您的情况下,foreach
循环)太慢,PLINQ将生成比必要更快的结果,并且仅在您完成迭代结果时才会停止。这意味着PLINQ会浪费CPU时间和内存。