我遇到过这样的情况,使用LINQ工作正常,但PLINQ导致“OutOfMemoryException”。以下是示例代码
static void Main(string[] args)
{
Stopwatch timer = new Stopwatch();
var guidList = new List<Guid>();
for (int i = 0; i < 10000000; i++)
{
guidList.Add(Guid.NewGuid());
}
timer.Start();
// var groupedList = guidList.GroupBy(f => f).Where(g => g.Count() > 1);
var groupedList = guidList.AsParallel().GroupBy(f => f).Where(g => g.Count() > 1);
timer.Stop();
Console.WriteLine(string.Format("Took {0} ms time with result: {1} duplications", timer.ElapsedMilliseconds, groupedList.Count()));
Console.ReadKey();
}
抛出内部异常“抛出类型'System.OutOfMemoryException'的异常”......可能是什么问题?在这种情况下使用PLINQ的准则是什么,提前谢谢。
答案 0 :(得分:3)
您可能接近常规Linq版本的内存不足,但使用AsParallel()
会增加额外的分区开销以并行运行,因此您可以超出限制。
当我尝试你的样本时,我首先得到了相同的结果,非并行版本将完成,但PLinq版本将耗尽内存 - 将Guid列表大小加倍然后导致两个版本内存不足。另请注意,1000万Guids在内存中占用大约152 MB的空间
另请注意,您当前的plinq和linq查询仅在Console.WriteLine()
中执行 - 因为Linq很懒,您必须强制进行评估,即使用ToList()
(或在您的情况下Count()
)
答案 1 :(得分:2)
至少抑制问题的一种方法是不将所有guid放入列表中,而是使用可枚举的。
public IEnumerable<Guid> getGuids(int number)
{
for (int i = 0; i < number; i++)
{
yield return Guid.NewGuid();
}
}
这有几个优点。首先,它是懒洋洋地加载的,所以你在处理过程中失败而不是guids的声明。其次,你并没有抓住所有未通过where子句的guid;它们可以从内存中删除。这意味着很多。你只需要在内存中拥有每个guid的一个副本,而不是在你点击where子句时有两个副本。