2009-08-04 6 views
4

In einem Projekt an dem ich arbeite, gibt es wirklich große Sammlungen (1 M-1B-Elemente), und die Dinge werden als Sammlungen meist modifiziert.Ihre eigene LINQ & IEnumerable Implementierung <T>

Es ist eine Echtzeit-App, und so ist die Leistung von größter Bedeutung.

Für einige der Operationen, wie umge, Binary (möglich?), Etc. werden mehr als andere, wie Wählen Sie leiden usw.

Ist es möglich, eine eigene IEnumerable mit möglichen Movenext des zu implementieren, MovePrev, etc. und eigene implementierte LINQ-Erweiterungen, die Vorteile daraus ziehen?

Wenn das passieren wird, wird es am Ende des Projekts passieren. Weil wir es zuerst arbeiten müssen, dann mach es schneller.

Alles in allem sollte das nicht zu viel Arbeit sein, oder?

+1

Es tut uns leid, aber es ist nicht klar, wie Sie einen Leistungszuwachs planen, indem Sie Ihre eigene Schnittstelle für Sequenzen rollen. Was ist hier genau geplant? Für welchen Code sorgen Sie sich und versuchen, ihn zu ersetzen? – mquander

+0

Ich würde hinzufügen, dass wenn Sie die Elemente Ihrer Sammlung in die Millionen nummerieren, Sie wahrscheinlich nicht alle im Speicher auf einmal speichern, richtig? Also ein naives Herangehen an das Retrieval wird sein, was Sie kostet, durch die Kosten für den Disketten- oder Netzwerkzugang oder was auch immer. Wenn Sie sich Sorgen um die Leistung machen, müssen Sie sich kompliziertere Abstraktionen als nur einfache Aufzählungen überlegen. – mquander

+0

Es ist wirklich breit, alle Details hier einzubeziehen, aber als einfaches Beispiel die Reverse-Funktionalität zum Beispiel oder BinarySearch eine Sammlung für WhereSorted oder etwas. –

Antwort

9

Es ist sehr durchaus möglich, eine eigene Implementierung von Enumerable die möglicherweise einen speziellen Fall, dass einige Situationen zu schaffen. Sie möchten grundsätzlich Ihre eigenen Sammlungsarten (oder möglicherweise nur Sammlungen wie List<T>) erkennen und gegebenenfalls eine effizientere Implementierung verwenden.

Ich habe eine sample project, die ich verwendet, um zu demonstrieren "LINQ zu Objekten in einer Stunde implementieren", die Sie gerne für Beispiele betrachten. Es ist keine vollständige Implementierung und insbesondere ist es weniger effizienter als das echte LINQ zu Objekten - aber Sie können es immer noch interessant finden.

Alternativ können Sie feststellen, dass i4o (Indexed LINQ) alles, was Sie brauchen, out-of-the-box - oder dass Sie besser dran wäre, als von Grund auf neu zu starten. Es lohnt sich auszuchecken.

Denken Sie daran, dass LINQ am Ende des Tages im Grunde ein schönes Design mit syntaktischen Zucker gekoppelt ist. Der C# -Compiler weiß nicht irgendetwas speziell über System.Linq.Enumerable, zum Beispiel.

+0

Danke Jon. Ich werde beide Projekte prüfen. Sie sagten "C# -Compiler weiß nichts besonderes ...", aber ich werde die Abfragesyntax verlieren, richtig? Oder wird der Compiler meinen verwenden, wenn die Namen übereinstimmen, wie Auswählen und Wo? –

+2

Letzteres. Der C# -Compiler kennt das * Muster *, aber nicht die Einzelheiten. Sie könnten das Abfragemuster über einen * total * anderen Typ implementieren, wenn Sie möchten. Weitere Informationen finden Sie in den Kapiteln 11 und 12 von C# in der Tiefe, falls Sie es haben. –

+0

Danke Jon. Ich habe es sicher.Fangen Sie noch nicht an, aber schauen Sie sich diese Kapitel an. –

2

Wenn Sie wirklich Leistung wollen, können Sie ziemlich viel tun. Beachten Sie, dass die folgende Auswahl:

var result = from element in collection 
      where element.Id == id 
      select element; 

Compiliert als:

var result = collection.Where(element => element.Id == id); 

Wenn Sie das folgende Verfahren für die Art der collection erstellen, dann können Sie die Tatsache ausnutzen, dass die primäre Aktion für Gleichheit der Id Mitglied und bearbeiten Sie die Anfrage in optimierter Weise. Das Wichtigste ist, die performance-kritischen Operationen in Ihrer Sammlung richtig zu identifizieren und die richtigen Algorithmen (d. H. Komplexität) auszuwählen, um sie auszuführen.

public IEnumerable<TElement> Where(Expression<Func<TElement, bool>> selector) 
{ 
    // detect equality of the Id member and return some special value 
} 
2

Betrachten System.Linq.Enumerable.Reverse() - diese Methode vollständig die IEnumerable aufzählt, bevor das erste Ergebnis zurück.

Wenn Ihre Abfrage ist myCollection.Reverse(). Take (10), und Ihre Sammlung hat Milliarden von Elementen, ist es eine schreckliche Idee, die Milliarden von Elementen zu zählen, um 10 zu bekommen.

Wenn Sie eine Reverse-Methode auf Ihrer eigene Art geliefert wird, können Sie eine bessere Umsetzung liefern, die einfach nach hinten über die Sammelschleife (durch den Index möglicherweise).

Der Schlüssel dazu ist die Bereitstellung eines eigenen Typs für die Steuerung der Implementierungen. Sie können die Implementierungen, die für alle IEnumerable<T> funktionieren, nicht verwenden, da diese Implementierungen die Möglichkeiten Ihres benutzerdefinierten Auflistungstyps nicht voll ausnutzen.

+0

Danke David, das ist ein gutes Beispiel, an das ich gedacht habe. –

1

Ist es möglich, das eigene IEnumerable mit möglichen Movenext zu implementieren, MovePrev, etc. und besitzen Erweiterungen LINQ implementiert, dass diese Vorteile von nehmen?

IEnumerable (oder richtiger, IEnumerator) nicht MovePrev. Sie könnten eine Schnittstelle definieren:

Dies könnte von jedem Container implementiert werden, der effiziente umgekehrte Aufzählung unterstützt.

Sie könnten dann eine Überladung von Reverse (die Erweiterungsmethode) schreiben, um diese neue Schnittstelle zu bearbeiten, und Auflistungsklassen, die die Schnittstelle implementieren usw. Und dann müssten Sie diese Auflistungsklassen anstelle von Standardklassen wie verwenden List<T>.

Aber (ich habe Reflektor nicht praktisch zu überprüfen) kann es sein, dass die eingebaute in Reverse klug genug ist, die Dinge die schnelle Art und Weise zu tun, wenn es die IList Schnittstelle aus der Sammlung bekommen kann, was die meisten optimieren würde übliche Fälle sind sowieso gut.

So gibt es möglicherweise nicht viel Sinn in dieser Art von Ansatz.

+0

Danke Earwicker. Auf diese Weise würde die richtige Methode über meine Sammlung aufgerufen, oder? d. h. es würde den Standard Reverse für MyCollection nicht aufrufen. –

+0

Bitte beachten Sie, dass es wahrscheinlich NICHT viel Sinn macht, dies zu tun. Und wenn Sie sicher sein wollen, dass eine bestimmte Methodenimplementierung aufgerufen wird, können Sie ihr immer einen neuen, anderen Namen geben. Dies hat den zusätzlichen Vorteil, dass Leute, die Ihren Code lesen, Ihre Absichten sowie den Compiler kennen. Aber ja, du könntest das tun. Aber laden Sie Reflector herunter und schauen Sie sich an, was Reverse für "IList" tut, bevor Sie zu irgendeiner manuellen Anstrengung gehen - ich weiß nicht, ob es anders handhabt, aber vielleicht. –

+0

Ich habe nichts mit IList im Reverse-Iterator gesehen. –

Verwandte Themen