Ich habe eine Methode, die Rekursion verwendet, um einen Baum zu durchlaufen und die Elemente zu aktualisieren.
Momentan dauert die Verarbeitung der Elemente ziemlich lange, also habe ich mit der Optimierung begonnen. Dazu gehört die Verwendung eines Wörterbuchs, anstatt eine DB-Abfrage für jedes Element auszuführen.
Das Wörterbuch ist als
definiert %Vor%Der Schlüsseltyp ist definiert als
%Vor%Wenn die Methode ausgeführt wird, werden etwa 5000 Rekursionen benötigt, um alle Elemente zu aktualisieren.
Anfangs dauerte es ungefähr 100 Sekunden ohne das Wörterbuch.
Ein erster Ansatz mit DB-Abfragen, die durch die Verwendung eines Wörterverzeichnisses mit int
keys ersetzt wurden, dauerte 22 Sekunden .
Nun, mit DB-Abfragen, die durch die Verwendung des oben definierten Wörterbuchs und richtiger Aufrufe von TryGetValue()
ersetzt wurden, dauert es 97 Sekunden & lt; - WAT.
Was ist hier los? Was könnte diesen massiven Leistungsabfall verursachen?
Bearbeiten
Zuerst schien es mir wie ein Hash-Kollisions-Problem zu sein, also fügte ich einen Haltepunkt in EffectivePermissionKey.Equals()
hinzu, um zu überprüfen, dass diese Methode aufgerufen wird, aber nicht aufgerufen wird, also keine Hash-Kollision.
Bearbeiten2
Jetzt bin ich verwirrt. Ich dachte, dass Equals()
nur aufgerufen wird, wenn der Hash-Code nicht entspricht. Nach dem Ausdrucken der Hashcodes meiner Schlüssel und der in TryGetValue()
verwendeten Schlüssel sehe ich, dass diese Codes übereinstimmen. Dann habe ich mir den Quellcode von Dictionary<>
angesehen und es gibt eine Zeile in FindEntry()
, die so aussieht:
Dies bedeutet, dass für jeden Elementschlüssel im Wörterbuch die GetHashCode()
und Equals()
aufgerufen werden, weil ich alle Elemente im Wörterbuch verarbeite, da die Elemente das Ergebnis der DB-Abfrage sind Ergebnisse wurden vor dem Wörterbuch-Ansatz sowieso verarbeitet.
Vergiss die Leute, tut mir leid, dass du dir Zeit genommen hast, meine Vorgehensweise war völlig falsch. Lass mich erzählen warum.
Das Problem wurde aus Gründen der Einfachheit gelöst:
%Vor%Wie Sie sehen können, eine DB-Abfrage pro Baumknoten.
Nun der fehlerhafte Ansatz zur Optimierung:
%Vor% Sie sehen jetzt, dass die Abfrage einmal ausgeführt wird, aber auf jedem Knoten ein TryGetValue()
-Aufruf erfolgt.
In meinem speziellen Fall ist dies tatsächlich langsamer als die Ausführung einzelner Abfragen, weil
und
jedes TryGetValue()
erfordert / ergibt
TryGetValue()
Equals()
Diese 4 Schritte werden ungefähr 5000 Mal ausgeführt, im Gegensatz zu 5000 einfachen Entity-Framework-Abfragen ( SELECT * FROM table WHERE ID = ...
). Ich weiß nicht warum, aber die Abfragen sind hier schneller, vielleicht optimiert der Compiler etwas weg.
Wie auch immer, ich habe die ganze Sache überarbeitet und jetzt habe ich eine äußere Schleife über Benutzer-IDs und eine innere rekursive Traversierung, die Wörterbücher mit einem einfachen int-Schlüssel (Knoten-ID) verwendet. Es gibt mir schnelle Ergebnisse. Die gesamte Ausführung dauert jetzt ungefähr 16 Sekunden und mit ein paar mehr Tweaks und Threading habe ich es auf unter 1 Sekunde geschafft. Mission erfüllt.
Tags und Links c# performance dictionary recursion