Jump to content

Powershell Performance erhöhen


Der letzte Beitrag zu diesem Thema ist mehr als 180 Tage alt. Bitte erstelle einen neuen Beitrag zu Deiner Anfrage!

Empfohlene Beiträge

Hallo Zusammen,

 

mit fehlt leider die Erfahrung um folgendes Script performanter zu machen. Leider finde ich auch nicht wirklich etwas im Netz dazu.

 

Generell liegt das Problem wahrscheinlich auch in der Größe der Log Datei, die durchsucht wird. Die Datei ist ca. 40GB groß.

In der Adressen.txt sind ca. 1000 E-Mail Adressen enthalten. Es muss geprüft werden, welche E-Mail Adresse in dem 40GB großen Dokument vorhanden ist.

Wenn es vorhanden ist, soll im Output-Dokument hinter der E-Mail ein "Ja" geschrieben werden.

Vielen Dank im Voraus!

 

Gruß Tim

$logFolder = "H:\logs.txt"
$adressen= Get-Content H:\Adressen.txt
$ergebnis = @()
    
foreach ($adr in $adressen){
    $suche =  Select-String -Path $logFolder -Pattern "\[\(\'from\'\,.*$adr.*\'\)\]" -List
    $aktiv= $false
    $adr
    if ($suche){
        $aktiv = $true 
    }

    if ($aktiv -eq $true){
        $ergebnis+=$adr + ";Ja"
    }
    else{
        $ergebnis+=$adr + ";Nein"
    }
}
$ergebnis |Out-File H:\output.txt

 

Link zu diesem Kommentar

Das Problem ist hier glaube ich weniger, dass das schreiben der Datei bzw. des Arrays so lange dauert. Die Überprüfung von einer Zeile (1x E-Mail) aus der Adressen.txt auf die ganze mail.log dauert mehrere Minuten, wenn diese nicht gefunden wird und somit natürlich bis zum ende durchsucht wird.

Leider weiss ich nicht, wie man jeweils immer 1000 Adressen auf eine zeile überprüfen würde. Wäre das wirklich schneller?

vor 12 Minuten schrieb testperson:

Hi,

 

wo kommt denn das Log her? Lässt sich das evtl. direkt in etwas performanteres wie eine einfache Textdatei schreiben (z.B. SQL)?

 

Gruß

Jan

Leider nur die Möglichkeit in diesem Format :(

Link zu diesem Kommentar

Hab mal das ganze nachgestellt.

Bei etwas über 1000 Adressen und einer Log Datei mit knapp 190 MB.

Dein Script läuft ca. 49 min, da (wie schon angemerkt) die große Datei bei jeder Adresse aufgemacht wird.

 

$adressen = Get-Content H:\Adressen.txt
$ergebnis = @()

foreach($line in (Get-Content "H:\logs.txt")){
   if($adressen.contains($line)){
      #$line # Nur Ausgabe, kann direkt in Output Datei gespeichert werden, wenn Dupletten erlaubt sind
      $ergebnis += $line # Zwischenspeichern, wenn Dupletten erlaubt sind, kann das weggelassen werden, wenn in der Zeile davor das Ergebnis gespeichert wird.
   }
}

$ergebnis | Sort-Object -Unique | Out-File H:\output.txt # Ergebnis OHNE Dupletten speichern
#$ergebnis | Out-File H:\output.txt # Ergebnis MIT Dupletten speichern

Je nachdem, ob du Dupletten erlauben willst oder nicht kannst du entsprechende Elemente auskommentieren.

Das Script läuft auf den gleichen Dateien wie oben ca. 12 Min.

Link zu diesem Kommentar

1. Wurde ja schon angemerkt - das Suchen von 1000 Adressen in jeder einzelnen Zeile geht schneller als die Logdatei 1000 mal zu lesen :-)

2. Umstellen - dringend. .Net Streamreader - das Inet liefert Dir das HowTo dazu. Get-Content ist um Potenzen langsamer.

3. += ist böse. Besser ein .Net ArrayList (oder wie das heißt :-) ) verwenden, auch da liefert das Inet.

4. Pipes vermeiden - immer und überall. Pipes sind auch schnarch...

Link zu diesem Kommentar
  • 2 Wochen später...

Ein Dictionary ist in der Regel noch schneller als eine Array. Zumindest so meine Erfahrung, auch wenn sich diese hauptsächlich auf VB6 beschränkt und meine Erfahrung etwas angestaubt ist. Denke aber, das wird in .Net nicht anders sein. =)

EDIT: Habe mal schnell in einer meiner Sources geschaut weil es mir grad unlogisch war weil der dic ja ein Objekt ist und die Elemente selber auch Objekte. Das heisst meist ist Dictonary eigentlich schneller als eine Collection nicht eines Arrays. Der Geschwindigkeitsvorteil gegenüber einem Array resultiert dann, wenn du das "Exist" als Vergleichsoperator benutzt. Also die zu vergleichenden Strings als Key hinzufügst. Der Grund ist, dass der Vergleich auf C++ Ebene innerhalb des Dics abläuft und nicht in der höheren Programmiersprache selber wo der Vergleich sowas wie  If A = B then ... heisst.  Je nach Programmiersprache ist der Unterschied deutlich spürbar oder nur minimal. Bei VB war das jeweils ziemlich heftig bei grösseren Datenmengen.

 

Eine Umsetzung in C++ gibt für "stupide" Massenverarbeitung in der Regel auch ein Performance-gewinn, ist aber (deutlich) mühsamer zu programmieren. Zumindest wenn man es sich nicht gewohnt ist. Da die Anforderungen hier nicht besonders gross sind, wärs vielleicht ein Versuch wert.

 

Dann helfen natürlich die üblichen Hardware-Empfehlungen wie möglichst hohe Taktrate, je nach Sofware und Programmierung die Anzahl Kerne und insbesondere die IOPS und RAM. Vielleicht würde auch eine RAM-Disk helfen oder das komplette laden der Datei ins RAM bzw. in die Software oder eben das vorherige Aufarbeiten der Daten/import in eine DB oder oder oder  ;-)

Dazu müsste man aber mehr zu dieser Logdatei wissen. Aufbau usw. sonst ist das schwer zu beurteilen. Oft läufts auch einfach auf Try and Error raus. ;)

 

Schlussendlich sollte man in solchen Fällen möglichst alle Register ziehen wenn man die Zeit nicht zu Verfügung stellen möchte.

bearbeitet von Weingeist
Link zu diesem Kommentar

@Dukel: Naja, 40GB an Textdaten nach Text zu durchsuchen ist irgendwie nie ein Spass. Wenn es mit 190MB und 1000 Adressen gerade mal 12min gegenüber 59min dauert, dann viel Spass bei 40GB. ;)

 

Das Ergebnis würde ich in deinem Beispiel auch so umschreiben, dass es ein boolscher Wert ist und nicht ein String. Erst die Auswertung ein String. Also Dics.Item('E-Mail-Addi') = true.

Am Ende dann den  Dics auswerten. Das ist mit Sicherheit schneller als String-Additionen die immer super lahm sind, insbesondere wie von daabm angemerkt wurde wenn der String immer neu allokiert werden muss. Da gibts zwar Apis die das noch schneller machen (keine Ahnung ob auch die von ihm angemerkten Streams), aber sinnvoll ist das eigentlich nie (bei solchen Datenmengen). Dann könnte man noch den Value des Dics-Eintrags testen vor dem Vergleich, ist er True (also bereits einmal gefunden) muss der Aufwendige Textvergleich für diese Adresse nicht mehr stattfinden. Er will am Ende ja nur wissen ob und nicht wie viele mal die Adresse vorhanden war.

bearbeitet von Weingeist
Link zu diesem Kommentar
Der letzte Beitrag zu diesem Thema ist mehr als 180 Tage alt. Bitte erstelle einen neuen Beitrag zu Deiner Anfrage!

Schreibe einen Kommentar

Du kannst jetzt antworten und Dich später registrieren. Falls Du bereits ein Mitglied bist, logge Dich jetzt ein.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor-Fenster leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...