Hallo Community! Ich habe folgendes Programm geschrieben: 3 Excellisten mit ca 5-6 Spalten werden jeweils als Datensatz eingelesen. (Diese Datensätze enthalten Informationen über Computer) 1 Eine Liste mit 10000 Hostnames wird eingelesen und jeder Hostname wird in den bereits 3 vorhanden Datensätzen gesucht. (Gesucht wird der Hostname in den Datensätzen mit Hilfe von Linq) Anschließend wird ein AssetComputerobjekt mit den Daten aus den 3 Listen + dem Hostname in einer List<ComputerObjekt> zwischengespeichert. Anschließend wird die List<ComputerObjekt> als CSV Datei gespeichert und das komplette Programm ist zuende. -- -> Jeder Hostname wird in einer Parallel.ForEach abgefragt (Das brachte bereits eine Zeitersparnis von 1 Minute.) -- Mit der Stopwatchklasse gemessen erhalte ich eine Zeit von 1 Min und 26 Sekunden für dieses Programm auf einem Intel(R) Core(TM) i5-4300U CPU @ 1.90GHz --- Wenn man überlegt wie schnell unsere Computer eigentlich sind, finde ich dass das Programm ziemlich langsam ist. Könnt ihr Abfragen in dieser Art als sehr zeitintensiv bestätigen oder scheint hier tatsächlich mein Programm sehr langsam zu sein? Gruß und Danke im Voraus!
Datensatz 1 -> 2652 Zeilen (3 Spalten) (unsortiert) Datensatz 2 -> 21148 Zeilen (9 Spalten) (unsortiert) Datensatz 3 -> 9500 Zeilen (1 Spalte) (Nach Name sortiert)
Du könntest die Datensätze in einem HashSet<T> speichern. Darin kann viel schneller gesucht werden.
csharplangsamfragezeichen schrieb: > Datensatz 1 -> 2652 Zeilen (3 Spalten) (unsortiert) > > Datensatz 2 -> 21148 Zeilen (9 Spalten) (unsortiert) > > Datensatz 3 -> 9500 Zeilen (1 Spalte) (Nach Name sortiert) allso müssen 23.800 unsortierte Zeilen 10.000 mal durchsucht werden, (es wird bekannt sein in welcher Spalte der Name steht?) macht im Durchschnitt 0.5*23800*10000 119.000.000 Vergleiche, wobei String vergleiche teuer werden wenn die Strings sich erst weit hinten unterscheiden, dann kommt noch Disk IO dazu, das kommt so schon hin. Und wenn deine Daten insgesamt über 3MB sind wird wahrscheinlich die Verbindung CPU-Ram limitierend sein. Bei 10.000 Suchen würde es die Sache wahrscheinlich beschleunigen wenn du aus den daten erst einen Suchbaum machst und den dann durchsuchst.
Du brauchst das Rad nicht neu zu erfinden. Lies die Daten in eine Datenbank ein (z.B. SQLite), dann lege Indexe auf die Spalten, in denen gesucht wird und frage die Daten per SQL ab.
> Und wenn deine Daten insgesamt über 3MB sind wird wahrscheinlich die > Verbindung CPU-Ram limitierend sein. > > Bei 10.000 Suchen würde es die Sache wahrscheinlich beschleunigen wenn > du aus den daten erst einen Suchbaum machst und den dann durchsuchst. Was genau meinst du mit Suchbaum?
>Du brauchst das Rad nicht neu zu erfinden. Lies die Daten in eine >Datenbank ein (z.B. SQLite) mit Kanonen auf Spatzen..
csharplangsamfragezeichen schrieb: > Wenn man überlegt wie schnell unsere Computer eigentlich sind, finde ich > dass das Programm ziemlich langsam ist. Könnt ihr Abfragen in dieser Art > als sehr zeitintensiv bestätigen oder scheint hier tatsächlich mein > Programm sehr langsam zu sein? Es wird in diesem Fall wohl an deinem Programm liegen. > Gesucht wird der Hostname in den Datensätzen mit Hilfe von Linq Ja, wie denn? Das ist das wichtige Detail hier. Sortiere doch mal die Listen 1 und 2 und suche in allen drei Listen nicht linear, sondern benutze zumindest List<T>.BinarySearch. https://msdn.microsoft.com/de-de/library/w4e7fxsh%28v=vs.100%29.aspx Allgemein: https://de.wikipedia.org/wiki/Bin%C3%A4re_Suche Ich gehe stark davon aus, dass das reichen würde. Optional kannst du dir auch mal Dictionary<TKey, TValue> ansehen. Wenn du LINQ verwenden willst: https://msdn.microsoft.com/de-de/library/vstudio/bb549277%28v=vs.100%29.aspx (& TryGetValue) Ob du zusätzlich in einem anderen Programmteil (beim Laden, der Objekterzeugung, dem Speichern, ...) einen Bock geschossen hast, können wir natürlich nicht wissen. > Jeder Hostname wird in einer Parallel.ForEach abgefragt (Das brachte > bereits eine Zeitersparnis von 1 Minute.) Das ist ein Indiz dafür, dass ich mit meiner Einschätzung nicht ganz falsch liege. Diese Verbesserung ist übrigens ganz und gar irrelevant im Vergleich zu den Unterschieden zwischen deiner (vermutlich schlimmstmöglichen nicht absichtlich bösartigen) Art zu suchen und einem besseren Algorithmus.
Nochmal: HashSet<T> macht bereits alles. Die interne Suche ist auf Geschwindigkeit optimiert (vergleichbar mit binärer Suche).
Andreas Richter schrieb: > HashSet<T> macht bereits alles. Die interne Suche ist auf > Geschwindigkeit optimiert (vergleichbar mit binärer Suche). Nicht ganz. Du hast zusätzlich immer die Generierung des Hashwerts plus das Suchen wenn an einem Knoten mehrere identische Hashwerte sind. Bei 10000 Suchen ist ein sortieren des Arrays und eine rein binäre Suche auf jeden Fall nochmal messbar schneller als suchen über eine Hashtabelle.
Robert L. schrieb: >>Du brauchst das Rad nicht neu zu erfinden. Lies die Daten in eine >>Datenbank ein (z.B. SQLite) > > mit Kanonen auf Spatzen.. Allerdings. Und (ohne jetzt selbst mit C# vertraut zu sein) würde ich einen Besen fressen wenn nicht in dessen mitgelieferten Standard-Libraries bereits fertige Funktionen für gängige schnelle Sortieralgorithmen und für binäre Suchen enthalten sind.
Andreas Richter schrieb: > Nochmal: > HashSet<T> macht bereits alles. Die interne Suche ist auf > Geschwindigkeit optimiert (vergleichbar mit binärer Suche). Wie genau würdest du ein HashSet in diesem Szenario verwenden (es gibt "Contains" (bool) und du kannst iterieren - wobei die Elemente nicht geordnet sind)? >> Anschließend wird ein AssetComputerobjekt mit den Daten aus den 3 Listen >> + dem Hostname in einer List<ComputerObjekt> zwischengespeichert. >> Anschließend wird die List<ComputerObjekt> als CSV Datei gespeichert
Ok, du meintest wahrscheinlich, dass man die Hostnamen dort hineinsteckt, über die drei Listen iteriert (also das Ganze quasi umkehrt) und dann bei Treffern Referenzen auf die Elemente speichert.
>> Gesucht wird der Hostname in den Datensätzen mit Hilfe von Linq > > Ja, wie denn? Das ist das wichtige Detail hier. > Gesucht wird direkt im Datensatz also so: IEnumerable<DataRow> query = from Zeile in die_erste_Liste.dataset.Tables[0].AsEnumerable() where (Zeile.Field<string>("EineSpalte").ToString().Contains(Inhalt) == true) && (Zeile.Field<string>("EineandereSpalte").ToString() == Inhalt2) select Zeile; > Sortiere doch mal die Listen 1 und 2 und suche in allen drei Listen > nicht linear, sondern benutze zumindest List<T>.BinarySearch. > > https://msdn.microsoft.com/de-de/library/w4e7fxsh%... > Ich sollte also auf jeden Fall den Weg vom Datensatz zur Liste / HashSet unternehmen ? > Allgemein: > https://de.wikipedia.org/wiki/Bin%C3%A4re_Suche > > Ich gehe stark davon aus, dass das reichen würde. > > Optional kannst du dir auch mal Dictionary<TKey, TValue> ansehen. Wenn > du LINQ verwenden willst: > > https://msdn.microsoft.com/de-de/library/vstudio/b... > > (& TryGetValue) > > Ob du zusätzlich in einem anderen Programmteil (beim Laden, der > Objekterzeugung, dem Speichern, ...) einen Bock geschossen hast, können > wir natürlich nicht wissen. Nein, 99,99% der Arbeitszeit liegt bei dem Linq Befehl, der 10000 mal aufgerufen wird. > >> Jeder Hostname wird in einer Parallel.ForEach abgefragt (Das brachte >> bereits eine Zeitersparnis von 1 Minute.) > > Das ist ein Indiz dafür, dass ich mit meiner Einschätzung nicht ganz > falsch liege. Diese Verbesserung ist übrigens ganz und gar irrelevant im > Vergleich zu den Unterschieden zwischen deiner (vermutlich > schlimmstmöglichen nicht absichtlich bösartigen) Art zu suchen und einem > besseren Algorithmus. Danke für eure Anregungen bis hierhin... :)
R. Rebentrost schrieb: > Ok, du meintest wahrscheinlich, dass man die Hostnamen dort > hineinsteckt, über die drei Listen iteriert (also das Ganze quasi > umkehrt) und dann bei Treffern Referenzen auf die Elemente speichert. Ja, richtig.
> R. Rebentrost schrieb: >> Ok, du meintest wahrscheinlich, dass man die Hostnamen dort [Anm.: >> HashSet] hineinsteckt, über die drei Listen iteriert (also das Ganze >> quasi umkehrt) und dann bei Treffern Referenzen auf die Elemente >> speichert. Gäbe es dann nicht das Problem, dass man nachträglich die jeweils 0 bis 3 zusammengehörigen Objekte in der Ergebnisliste (bzw. den Ergebnislisten) suchen müsste? Wenn man dagegen List<T>.BinarySearch verwendet (*) und jeden Hostnamen direkt nacheinander in Liste (**) 1, 2 und 3 sucht, kann man die kompletten Datensätze sofort ohne Umwege zusammensetzen. (*) oder jeweils ein Dictionary (**) bzw. Dictionary
Beim CSV-Lesen eine HashMap o.ä. mit dem Hostname als Key anlegen. Ich brauchte gerade ein übersichtliches Beispiel, um wachzuwerden und mich an das neuinstallierte Eclipse zu gewöhnen und habe eine Mickeymausversion von einem vergleichbaren Problem in dreckigem C++ (kann kein C#) getippt, die ein wenig schneller läuft.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.