Использование PLINQ, вызывающее исключение OutofMemory, но не с LINQ? - PullRequest
2 голосов
/ 07 февраля 2012

Я сталкивался со сценарием, где использование 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 ]

3 голосов
/ 07 февраля 2012

Вы, вероятно, близки к нехватке памяти и в обычной версии Linq, но использование AsParallel() добавит дополнительные накладные расходы на разделение для параллельной работы, и из-за этого вы превысите предел.

Когда я попробовал ваш пример, у меня сначала были те же результаты, непараллельная версия закончилась, но версия PLinq исчерпала бы память - удвоение размера списка Guid привело к тому, что обе версии исчерпали память.Также обратите внимание, что 10 миллионов Guids занимают в памяти около 152 МБ

Также обратите внимание, что ваши текущие запросы plinq и linq выполняются только в вашем Console.WriteLine() - так как Linq ленив, вы должны форсировать оценку, т.е. использовать ToList() (или в вашем случае Count())

2 голосов
/ 07 февраля 2012

Один из способов хотя бы смягчить проблему - не помещать все направляющие в список, а использовать перечислимые.

public IEnumerable<Guid> getGuids(int number)
{
    for (int i = 0; i < number; i++)
    {
        yield return Guid.NewGuid();
    }
}

Это имеет несколько преимуществ.Во-первых, он загружается лениво, поэтому вы не сможете выполнить обработку, а не объявление направляющих.Во-вторых, вы не держитесь за все направляющие, которые не соответствуют предложению where;они могут быть удалены из памяти.Это много значит.Вам понадобится только одна копия каждой направляющей в памяти, а не две, когда вы нажмете предложение where.

...