Linq Speicher Frage

8

Da ich linq ziemlich neu bin, möchte ich fragen, ob mein Verständnis im folgenden Beispiel stimmt.

Nehmen wir an, ich habe eine sehr große Sammlung von Tiernamen (100k Datensätze), ich möchte sie filtern und die gefilterten Elemente in einer sehr zeitaufwendigen Methode (2 Wochen) verarbeiten. Die Methoden RunWithLinq() und RunWithoutLinq() sind identisch.

Stimmt das, dass bei Verwendung der ersten Methode die ursprüngliche (große) Sammlung nach dem Verlassen der Methode im Speicher verbleibt und nicht von GC berührt wird, während bei Verwendung der linq-less-Methode die Sammlung um% entfernt wird co_de%?

Ich wäre dankbar für eine Erklärung.

%Vor%     
nan 29.11.2010, 15:03
quelle

3 Antworten

7

Nun, animals wird am Ende jeder Methode für die Sammlung ausgewählt, daher ist Ihre Aussage streng falsch. animals wird früher im Nicht-LINQ-Fall für die Erfassung infrage kommen, sodass der Kern Ihrer Anweisung wahr ist.

Es stimmt, dass die Speicherbenutzung von jedem unterschiedlich ist. Es gibt jedoch eine Implikation, dass LINQ im Allgemeinen schlechter in Bezug auf die Speichernutzung ist, während es in der Realität sehr oft eine viel bessere Speichernutzung erlaubt als die andere Art von Ansatz (obwohl es Nicht-LINQ-Möglichkeiten gibt, dasselbe zu tun der LINQ-Weg, ich war ziemlich begeistert von der gleichen grundlegenden Ansatz für dieses spezielle Problem, wenn ich .NET2.0 verwendet.)

Betrachten wir zuerst die beiden Methoden, nicht LINQ:

%Vor%

Es ist zwei Dinge wert. Ein "förderungswürdiges" Sammeln bedeutet nicht, dass die Sammlung zu diesem Zeitpunkt stattfindet, sondern dass es zu irgendeinem Zeitpunkt in der Zukunft möglich ist. Zwei, Sammlung kann passieren, während ein Objekt noch im Bereich ist, wenn es nicht wieder verwendet wird (und sogar in einigen Fällen, wo es verwendet wird, aber das ist eine andere Detailstufe). Bereichsregeln beziehen sich auf die Programmquelle und sind eine Frage dessen, was passieren kann, wenn das Programm geschrieben wird (der Programmierer kann Code hinzufügen, der das Objekt verwendet), GC-Erfassungsberechtigungsregeln beziehen sich auf das kompilierte Programm und sind eine Frage dessen, was passiert ist Programm wurde geschrieben (der Programmierer könnte solchen Code hinzugefügt haben, aber sie haben nicht).

Sehen wir uns nun den Fall LINQ an:

%Vor%

Also hier in diesem Fall kann keines der relevanten Objekte bis zum Ende gesammelt werden.

Beachten Sie jedoch, dass filtered niemals ein großes Objekt ist. Im ersten Fall ist filtered eine Liste, die irgendwo im Bereich von 0 bis n Objekten enthält, wobei n die Größe von animals ist. Im zweiten Fall ist filtered ein Objekt, das bei animals nach Bedarf arbeitet und an sich im Wesentlichen konstanten Speicher hat.

Daher ist der Spitzenspeicherverbrauch der Nicht-LINQ-Version höher, da es einen Punkt gibt, an dem animals noch vorhanden ist und filtered alle relevanten Objekte enthält. Wenn die Größe von animals mit Änderungen am Programm zunimmt, ist es wahrscheinlich die Nicht-LINQ-Version, die am ehesten einen schwerwiegenden Speichermangel verursacht, da der Spitzenspeicher-Verwendungszustand in der Nicht-LINQ-Klasse schlechter ist Fall.

Eine andere Sache, die wir in Betracht ziehen sollten, ist, dass in einem realen Fall, in dem wir genug Punkte hatten, um uns Gedanken über den Speicherverbrauch zu machen, unsere Quelle keine Liste sein wird. Überlegen Sie:

%Vor%

Dieser Code liest eine Textdatei und gibt jede Zeile gleichzeitig zurück. Wenn jede Zeile den Namen eines Tieres hätte, könnten wir dies anstelle von var animals als Quelle für filtered verwenden.

In diesem Fall wird in der LINQ-Version nur sehr wenig Speicher verwendet (nur ein Tiername muss immer im Speicher sein), während die Nicht-LINQ-Version viel mehr Speicher verwendet (Laden jedes Tiernamens, der mit " "in Erinnerung vor weiterer Handlung". Die LINQ-Version beginnt ebenfalls mit der Verarbeitung nach höchstens einigen Millisekunden, während die Nicht-LINQ-Version zuerst alles laden muss, bevor sie eine einzige Arbeit erledigen kann.

Daher könnte die LINQ-Version problemlos mit Gigabytes an Daten umgehen, ohne mehr Arbeitsspeicher zu benötigen als für eine Handvoll, während die Nicht-LINQ-Version mit Speicherproblemen kämpfen würde.

Schließlich ist es wichtig zu beachten, dass dies nicht wirklich etwas mit LINQ selbst zu tun hat, was Unterschiede zwischen der Vorgehensweise, die Sie mit LINQ vornehmen, und der Vorgehensweise ohne LINQ ist. Verwenden Sie:

, um das LINQ, das dem Nicht-LINQ entspricht, zu verwenden %Vor%

Um das LINQ-Äquivalent zum LINQ zu verwenden, verwenden Sie

%Vor%

Hier definieren Sie auch:

%Vor%

Was .NET 2.0-Techniken verwendet, aber Sie können dasselbe auch mit .NET 1.1 (wenn auch mit mehr Code) tun, wenn Sie ein Objekt erstellen, das von IEnumerable

abgeleitet ist     
Jon Hanna 29.11.2010, 15:52
quelle
3

Die LINQ-basierte Methode behält die ursprüngliche Sammlung im Speicher, speichert jedoch keine separate Sammlung mit den gefilterten Elementen.

Um dieses Verhalten zu ändern, rufen Sie .ToList() auf.

    
SLaks 29.11.2010 15:07
quelle
2

Ja, das stimmt - weil die Variable filtered im Wesentlichen die Abfrage ist, nicht die Ergebnisse der Abfrage. Beim Iterieren wird die Abfrage jedes Mal erneut ausgewertet.

Wenn Sie sie gleich machen wollen, können Sie einfach ToList :

aufrufen %Vor%

(Ich habe es von der Abfrageausdrucksyntax in "Punktnotation" umgewandelt, weil es in diesem Fall einfacher ist.)

    
Jon Skeet 29.11.2010 15:06
quelle

Tags und Links