Вопрос по linq-to-sql, .net, ienumerable, c#, yield – Как предотвратить переполнение памяти при использовании IEnumerable <T> и Linq-To-Sql?

1

Этот вопрос связан смой предыдущий вопрос

Это мой текущий код

<code> IEnumerable<Shape> Get()
 {
     while(//get implementation
         yield return new Shape(//...
 }

 void Insert()
 {
       var actual = Get();
       using (var db = new DataClassesDataContext())
       {
           db.Shapes.InsertAllOnSubmit(actual);
           db.SubmitChanges();
       }
 }
</code>

У меня переполнение памяти, поскольку IEnumerable слишком велик. Как мне это предотвратить?

Ваш Ответ

4   ответа
2

чтобы разбить входные данные на подмножества подходящего размера

public static class IEnumerableExtensions
{
    public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max)
    {
        List<T> toReturn = new List<T>();
        foreach(var item in source)
        {
            toReturn.Add(item);
            if (toReturn.Count == max)
            {
                yield return toReturn;
                toReturn = new List<T>();
            }
        }
        if (toReturn.Any())
        {
            yield return toReturn;
        }
    }
}

затем сохранить подмножества

void Insert()
{
    var actual = Get();
    using (var db = new DataClassesDataContext())
    {
        foreach (var set in actual.InSetsOf(5))
        {
            db.Shapes.InsertAllOnSubmit(set);
            db.SubmitChanges();
        }
    }
}

Вы также можете найтиэта статья MSDN на InsertOnSubmit () против InsertAllOnSubmit (), чтобы быть полезным.

Используйте toReturn.Clear () вместо toReturn = new List, чтобы избежать накладных расходов. Это похоже наstackoverflow.com/questions/1008785/… но немного более явно.
Очистка списка вместо создания нового имеет побочный эффект от неожиданного изменения результата, который был ранее возвращен, проблема, если он еще не использовался вызывающей стороной. Например: Enumerable.Range (1, 100) .InSetsOf (5) .InSetsOf (5) .ToList (). ForEach (x = & Console.WriteLine (x.First (). First () + & quot; - & & quot) ; + x.Last (). Last ())); получает 1-25 26-50 51-75 76-100 как закодированный, но 21-25 46-50 71-75 96-100, если список только очищен. Кроме того, поскольку GroupBy не используется, он может лениво возвращать результаты вместо того, чтобы сначала использовать весь ввод.
3

буферShape объекты, итерации, пока вы не заполните его или не закончите из перечислителя, затем выполнитеInsertBatchOnSubmit.

Ссылка на Earwicker имеет отличный пример. Я не уверен, что это поможет вам, так как вы делаете отсроченное исполнение, хотя. Возможно, вам понадобится список & lt; Shape & gt; и batchSize = 5 вне цикла. Добавьте элементы из вашего перечислителя, вставьте, как только счет достигнет размера batchSize, а затем очистите предыдущий пакет. Это то, что вы спрашивали?
Я понял, что InsertBatchOnSubmit будет InsertAllOnSubmit с меньшим количеством элементов Jader Dias
Как бы я получить все элементы в группах по 5? Jader Dias
3

InsertOnSubmit скорее, чемInsertAllOnSubmit, А затем совершать через определенные промежутки времени, как сказал Эрих.

Или, если вы хотите сделать это партиями, например, 5, попробуйHandcraftsman & APOS; s или жеDTB & APOS; s решения для получения IEnumerable'ов IEnumerable. Например, с помощью фрагмента dtb:

   var actual = Get();
   using (var db = new DataClassesDataContext())
   {
       foreach(var batch in actual.Chunk(5))
       {
         db.Shapes.InsertAllOnSubmit(batch);
         db.SubmitChanges();
       }
   }
1

смотрите это:

C #: Самый простой способ разделить массив строк на N экземпляров длиной N элементов

Обновление: не хорошо, это работает на массивах. Если у меня будет какое-то время спустя и никто ничего не предоставит, я напишу это ...

См. «Обновление». часть моего ответа! Я готовлю ужин прямо сейчас ...
@ Хорошая идея, чувак! Jader Dias
Будет ли это работать в его случае? Он не знает размер, поскольку у него есть только IEnumerable.
Эрик Липперт указал Эриху на решение (stackoverflow.com/questions/1008785#answer-1008855). dtb дал функцию, которая принимает IEumearable & lt; T & gt; и возвращает IEnumerable & lt; IEnumerable & lt; T & gt; & gt ;. Каждый из внутренних IEnumerable & lt; T & gt; имеет до (например) 5 элементов.

Похожие вопросы