2009-06-23 1 views
1

Этот вопрос связан с a previous question of mineКак предотвратить переполнение памяти при использовании IEnumerable <T> и Linq-To-Sql?

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

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(); 
     } 
} 

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

ответ

3

Используйте InsertOnSubmit, а не InsertAllOnSubmit. И затем совершите соответствующие промежутки времени, как сказал Эрих.

Или, если вы хотите сделать это партиями, например. 5, попробуйте Handcraftsman's или dtb's решения для получения IEnumerable в IEnumerable. Например, с Chunk DTB по:

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

Один из вариантов - разбить его на несколько партий. Создайте временный буфер Shape объектов, итерации до тех пор, пока вы его не заполните или не закончите из перечислителя, затем выполните InsertBatchOnSubmit.

+0

Как я могу получить все элементы в группах по 5? –

+0

Я понял, что InsertBatchOnSubmit будет InsertAllOnSubmit с меньшим количеством элементов. –

+1

Ссылка у Earwicker имеет отличный пример. Я не уверен, что это поможет вам, так как вы делаете отложенное исполнение. Возможно, вам придется иметь список и batchSize = 5 вне цикла. Добавьте элементы из вашего счетчика, вставьте один раз, когда счетчик достигнет размера пакета, а затем удалите предыдущую партию. Это то, о чем вы спрашивали? –

1

Для аккуратного способа получить партии деталей из IEnumerable, увидеть это:

C#: Cleanest way to divide a string array into N instances N items long

Update: Нет хороший, который работает на массивах. Если у меня есть некоторое время спустя, и никто еще не предоставил что-то, я напишу его ...

+0

@ хорошая идея человек! –

+0

Будет ли это работать в его случае? Он не знает размер, так как у него только IEnumerable. –

+0

См. Часть «Обновить» моего ответа! Я готовлю ужин прямо сейчас ... –

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(); 
     } 
    } 
} 

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

+0

Используйте toReturn.Clear(), а не toReturn = новый список, чтобы избежать накладных расходов. Это похоже на http://stackoverflow.com/questions/1008785/c-cleanest-way-to-divide-a-string-array-into-n-instances-n-items-long/1008974#answer-1008855, но немного более явным. –

+0

Устранение списка вместо создания нового имеет побочный эффект неожиданного изменения результата, который был ранее возвращен, проблема, если он еще не был использован абонентом. Например: Enumerable.Range (1, 100) .InSetsOf (5) .InSetsOf (5) .ToList(). ForEach (x => Console.WriteLine (x.First(). First() + "-" + x.Last(). Last())); получает 1-25 26-50 51-75 76-100 , как закодированный, но 21-25 46-50 71-75 96-100 если список только очищено. Кроме того, поскольку GroupBy не используется, он может лениво возвращать результаты, а не сначала потреблять весь вход. – Handcraftsman

Смежные вопросы