Как предотвратить переполнение памяти при использовании IEnumerable < > и Linq-To-Sql?
-
06-07-2019 - |
Вопрос
Этот вопрос связан с моим предыдущим вопросом
Это мой текущий код
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 слишком велик. Как мне это предотвратить?
Решение
Попробуйте использовать InsertOnSubmit вместо < a href = "http://msdn.microsoft.com/en-us/library/bb763476(VS.100).aspx" rel = "nofollow noreferrer"> InsertAllOnSubmit . А затем фиксируйте через определенные промежутки времени, как сказал Эрих.
Или, если вы хотите сделать это, например, партиями 5, попробуйте Handcraftsman's или dtb's решения для получения IEnumerable's IEnumerable. Например, с помощью dtb's Chunk:
var actual = Get();
using (var db = new DataClassesDataContext())
{
foreach(var batch in actual.Chunk(5))
{
db.Shapes.InsertAllOnSubmit(batch);
db.SubmitChanges();
}
}
Другие советы
Один из вариантов - разбить его на несколько партий. Создайте временный буфер объектов Shape
, выполняйте итерацию до тех пор, пока вы не заполните его или не исчерпаете счетчик, а затем выполните InsertBatchOnSubmit
.
Используйте следующий метод расширения, чтобы разбить входные данные на подмножества соответствующего размера
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 () может быть полезной.
Для удобного способа получить партии элементов из IEnumerable, смотрите это:
C #: самый простой способ разделить строковый массив на N экземпляров длиной N элементов
Обновление: не очень хорошо, это работает на массивах. Если у меня будет какое-то время спустя и никто ничего не предоставит, я напишу это ...