Forum: PC-Programmierung C# Performence-Frage


von csharplangsamfragezeichen (Gast)


Lesenswert?

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!

von Christian V. (michse)


Lesenswert?

wie groß sind die ersten drei Datensätz, und sind die sortiert?

von csharplangsamfragezeichen (Gast)


Lesenswert?

Datensatz 1 -> 2652 Zeilen  (3 Spalten) (unsortiert)

Datensatz 2 -> 21148 Zeilen (9 Spalten) (unsortiert)

Datensatz 3 -> 9500 Zeilen (1 Spalte) (Nach Name sortiert)

von Andreas R. (andreasr)


Lesenswert?

Du könntest die Datensätze in einem HashSet<T> speichern. Darin kann 
viel schneller gesucht werden.

von Christian V. (michse)


Lesenswert?

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.

von Klaus P (Gast)


Lesenswert?

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.

von csharplangsamfragezeichen (Gast)


Lesenswert?

> 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?

von Robert L. (lrlr)


Lesenswert?

>Du brauchst das Rad nicht neu zu erfinden. Lies die Daten in eine
>Datenbank ein (z.B. SQLite)

mit Kanonen auf Spatzen..

von R. Rebentrost (Gast)


Lesenswert?

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.

von Andreas R. (andreasr)


Lesenswert?

Nochmal:
HashSet<T> macht bereits alles. Die interne Suche ist auf 
Geschwindigkeit optimiert (vergleichbar mit binärer Suche).

von Udo S. (urschmitt)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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.

von R. Rebentrost (Gast)


Lesenswert?

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

von R. Rebentrost (Gast)


Lesenswert?

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.

von csharplangsamfragezeichen (Gast)


Lesenswert?

>> 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... :)

von csharplangsamfragezeichen (Gast)


Lesenswert?

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.

von R. Rebentrost (Gast)


Lesenswert?

> 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

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

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
Noch kein Account? Hier anmelden.