Pregunta sobre c#, ienumerable, yield, .net, linq-to-sql – ¿Cómo evitar el desbordamiento de memoria cuando se utiliza un IEnumerable <T> y Linq-To-Sql?

1

Esta pregunta está relacionada conuna pregunta previa mia

Ese es mi código actual

<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>

Tengo un desbordamiento de memoria, ya que IEnumerable es demasiado grande. ¿Cómo lo prevengo?

Tu respuesta

4   la respuesta
3

InsertOnSubmit más bien queInsertAllOnSubmit. Y luego cometer en intervalos apropiados, como dijo Erich.

O, si quieres hacerlo en lotes de, por ejemplo, 5, pruebaArtesano ode dtb Soluciones para obtener IEnumerable's de IEnumerable. Por ejemplo, con trozo de dtb:

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

Una opción es dividirlo en varios lotes. Crear un búfer temporal deShape objetos, itere hasta que los llene o se agote en el enumerador, luego haga unaInsertBatchOnSubmit.

Entendí que InsertBatchOnSubmit sería un InsertAllOnSubmit con menos elementos Jader Dias
¿Cómo obtendría todos los elementos en grupos de 5? Jader Dias
El enlace de Earwicker tiene un excelente ejemplo. Sin embargo, no estoy seguro de que eso te ayude ya que estás haciendo una ejecución diferida. Es posible que tenga que tener una lista <Shape> y batchSize = 5 fuera de un bucle. Agregue elementos de su enumerador, inserte una vez que el recuento alcance el batchSize y luego borre el lote anterior. ¿Es eso lo que preguntabas? Erich Mirabal
2

juntos de tamaño apropiado

<code>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;
        }
    }
}
</code>

luego persisten los subconjuntos

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

También podría encontrareste artículo de MSDN en InsertOnSubmit () vs InsertAllOnSubmit () para ser útil.

Use toReturn.Clear () en lugar de toReturn = new List para evitar la sobrecarga. Esto es similar astackoverflow.com/questions/1008785/… Pero un poco más explícito. Matthew Flaschen
Borrar la lista en lugar de crear uno nuevo tiene el efecto secundario de cambiar inesperadamente el resultado que se devolvió anteriormente, un problema si aún no ha sido consumido por la persona que llama. Por ejemplo: Enumerable.Range (1, 100) .InSetsOf (5) .InSetsOf (5) .ToList (). ForEach (x => Console.WriteLine (x.First (). Primero () + "-" + x .Ultimo ultimo())); obtiene 1-25 26-50 51-75 76-100 como codificado, pero 21-25 46-50 71-75 96-100 si la lista solo se borra. Además, dado que GroupBy no se usa, puede dar resultados perezosamente en lugar de consumir primero toda la entrada. Handcraftsman
1

erable, vea esto:

C #: La forma más limpia de dividir una matriz de cadenas en N instancias N elementos largos

Actualización: No es bueno, eso funciona en arreglos. Si tengo tiempo más tarde y nadie más me ha proporcionado algo, lo escribiré ...

@ buen hombre idea! Jader Dias
¡Vea la parte de 'actualización' de mi respuesta! Estoy cocinando la cena ahora mismo ... Daniel Earwicker
¿Funcionaría eso en su caso? Él no sabe el tamaño ya que solo tiene un IEnumerable. Erich Mirabal
Eric Lippert señaló a Erich en la solución (stackoverflow.com/questions/1008785#answer-1008855). dtb dio una función que toma un <T> de IEumearable y devuelve un <Enumerable <T>>. Cada uno de los <T> IEnumerables internos tiene hasta (por ejemplo) 5 elementos. Matthew Flaschen

Preguntas relacionadas