2009-06-23 2 views
4

Lorsque je dois obtenir des Go de données, les enregistrer sur une collection et les traiter, j'ai des débordements de mémoire. Ainsi, au lieu de:Quelle est la meilleure façon d'améliorer l'utilisation de la mémoire lorsque vous collectez un grand ensemble de données avant de le traiter? (.NET)

public class Program 
{ 
    public IEnumerable<SomeClass> GetObjects() 
    { 
     var list = new List<SomeClass>(); 
     while(// get implementation 
      list.Add(object); 
     } 
     return list; 
    } 

    public void ProcessObjects(IEnumerable<SomeClass> objects) 
    { 
     foreach(var object in objects) 
      // process implementation 
    } 

    void Main() 
    { 
     var objects = GetObjects(); 
     ProcessObjects(objects); 
    } 
} 

J'ai besoin de:

public class Program 
{ 
    void ProcessObject(SomeClass object) 
    { 
     // process implementation 
    } 

    public void GetAndProcessObjects() 
    { 
     var list = new List<SomeClass>(); 
     while(// get implementation 
      Process(object); 
     } 
     return list; 
    } 

    void Main() 
    { 
     var objects = GetAndProcessObjects(); 
    } 
} 

Il y a une meilleure façon?

+0

Quel type de données est-il une table de base de données, un fichier ascii, un fichier xml? – tuinstoel

+2

Vous devez être capable de raisonner sur l'ensemble en une fois, c'est-à-dire, pouvez-vous obtenir un petit morceau, traiter un petit morceau et ensuite répéter au lieu d'avoir tout en mémoire à une fois? –

+0

Appuyant la question de JP, avez-vous besoin de la liste < > dans le deuxième échantillon? –

Répondre

9

Vous devez tirer parti de la déclaration C# 's iterator blocks et utiliser le yield return faire quelque chose comme ceci:

public class Program 
{ 
    public IEnumerable<SomeClass> GetObjects() 
    { 
     while(// get implementation 
      yield return object; 
     } 
    } 

    public void ProcessObjects(IEnumerable<SomeClass> objects) 
    { 
     foreach(var object in objects) 
      // process implementation 
    } 

    void Main() 
    { 
     var objects = GetObjects(); 
     ProcessObjects(objects); 
    } 
} 

Cela vous permettra de diffuser chaque objet et non garder la séquence entière en mémoire - vous ne devez Gardez un objet en mémoire à la fois.

+0

N'a pas résolu mon problème. Lorsque je fais Table.InsertAllOnSubmit (objets), le débordement de mémoire se produit toujours. –

+0

http://stackoverflow.com/questions/1034429/how-to-prevent-memory-overflow-when-using-an-ienumerablet –

6

N'utilisez pas de liste, qui nécessite que toutes les données soient présentes en même temps dans la mémoire. Utilisez IEnumerable<T> et produisez les données à la demande, ou mieux, utilisez IQueryable<T> et faites différer l'exécution complète de la requête jusqu'à ce que les données soient requises.

Sinon, ne gardez pas du tout les données en mémoire, mais enregistrez les données dans une base de données pour traitement. Une fois le traitement terminé, interrogez la base de données pour connaître les résultats.

+0

Maintenant, je vais devoir demander comment implémenter votre solution IQueryable. –

+0

L'utilisation de l'un des fournisseurs LINQ renvoie une valeur IQueryable . –

1

Vous voulez yield!

Retarder le traitement de votre énumération. Construire une méthode qui renvoie un IEnumerable mais ne renvoie qu'un enregistrement à la fois en utilisant l'instruction yield.

3
public IEnumerable<SomeClass> GetObjects() 
    { 

     foreach(var obj in GetIQueryableObjects 
      yield return obj 
    } 
+0

Je pense que vous vouliez dire "yield return". –

+0

oui désolé de la syntaxe – Rony

1

La meilleure méthode dans ce cas serait d'obtenir et de traiter en blocs. Vous devrez déterminer la taille d'un bloc à obtenir et à traiter par essais et erreurs. Ainsi, le code serait quelque chose comme:

public class Program 

{ IEnumerable publics getObjects (ancrage int, int chunkSize) { liste var = new List(); while (// obtenir la mise en œuvre pour l'ancre donnée et chunkSize list.Add (objet);} liste de retour;? }

public void ProcessObjects(IEnumerable<SomeClass> objects) 
{ 
    foreach(var object in objects) 
     // process implementation 
} 

void Main() 
{ 
    int chunkSize = 5000; 
    int totalSize = //Get Total Number of rows; 
    int anchor = //Get first row to process as anchor; 
    While (anchor < totalSize) 
    (
     var objects = GetObjects(anchor, chunkSize); 
     ProcessObjects(objects); 
     anchor += chunkSize; 
    } 
} 

}

Questions connexes