Использование PLINQ вызывает исключение OutofMemory, но не с LINQ?
Я наткнулся на сценарий, где использование 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 для этого типа сценария, заранее спасибо.
2 ответа:
Вы, вероятно, близки к исчерпанию памяти в обычной версии Linq, но использование
AsParallel()
добавит дополнительные накладные расходы на секционирование, чтобы работать параллельно, и из-за этого вы превысите лимит.Когда я попробовал ваш образец, у меня сначала были те же результаты, непараллельная версия заканчивалась, но версия PLinq заканчивалась памятью-удвоение размера списка Guid затем приводило к тому, что обе версии заканчивались памятью. Также обратите внимание, что 10 миллионов GUID занимают около 152 МБ пространства в память
Также обратите внимание, что ваши текущие запросы plinq и linq выполняются только в вашем
Console.WriteLine()
- поскольку Linq ленив, вы должны принудительно выполнить оценку, т. е. используяToList()
(или в вашем случаеCount()
)
Один из способов, по крайней мере, ослабить проблему, состоит в том, чтобы не помещать все GUID в список, а использовать перечисляемый.
public IEnumerable<Guid> getGuids(int number) { for (int i = 0; i < number; i++) { yield return Guid.NewGuid(); } }
Это имеет несколько преимуществ. Во-первых, он лениво загружен, поэтому вы потерпите неудачу в середине обработки, а не в объявлении GUID. Во-вторых, вы не удерживаете все GUID, которые не соответствуют предложению where; они могут быть удалены из памяти. Это очень много значит. Вам нужно будет иметь только одну копию каждого guid в памяти, а не две, когда вы нажмете предложение WHERE.