Frage Warum ist Powershell so langsam?


Ich habe versucht, mit PowerShell eine einfache Sache zu machen, finde Dateien, die am meisten Speicherplatz auf dem Laufwerk einnehmen. ich benutzte ls + sort und ... es dauerte ewig für mich.

Manchmal benutze ich Far Manager und im Vergleich zu PowerShell sieht es viel schneller und stabiler aus.

Ok, es basiert auf .NET, aber .NET ist nicht so langsam. Ich erwarte etwas Leichtes und Schnelles zu sehen! Es ist Konsole!

Eine andere Sache, möchte ich etwas wie haben IEnumerable in PowerShell, um sofort Ergebnisse zu sehen. Ist es möglich zu erreichen? Es kann ein wenig helfen, während ich Ergebnisse erwarte, weil ich manchmal denke, dass es einfach nur rumhängt.

BEARBEITEN

Ich mache so etwas

ls -Recurse -ErrorAction SilentlyContinue | sort -Property Size | select -First 10

Und ich denke, es könnte Tage dauern.

BEARBEITEN

Nur um zu vergleichen.

C # -Code dauerte für mich ca. 2 min. Sicher ist es nicht ideal und hat nicht alle Dateien verarbeitet, aber es hat mindestens> 95% verarbeitet.

void Main()
{
    GetFilesSize(@"C:\").OrderByDescending(x => x).Take(10).ToList();
}

public IEnumerable<long> GetFilesSize(string directory)
{
    var accessDenied = false;
    var dirList = new string[0]; 
    try
    {
        dirList = Directory.GetDirectories(directory);
    }
    catch{
        accessDenied = true;
    }

    if(accessDenied) yield break;

    foreach (var dir in dirList)
    {
        foreach (var size in GetFilesSize(dir))
        {
            yield return size;
        }
    }

    foreach (var fileName in Directory.GetFiles(directory))
    {
        if(fileName.Length>=260) continue;
        yield return new FileInfo(fileName).Length;
    }
}

4
2018-05-13 01:47


Ursprung


"Noch etwas ..." Nein, bitte, nein! Stellen Sie keine zweite Frage, die in derselben Frage zusätzliche / unterschiedliche / nicht zusammenhängende Antworten generiert. Erstellen Sie einfach eine neue SuperUser-Frage. - TOOGAM
wäre sehr nützlich, um Ihren Code zu sehen, der "so langsam" ist, weil es vielleicht nicht PowerShell ist, sondern eher Ihr Code! - SimonS
Willkommen zu Superbenutzer! Bitte versuchen Sie, eine Frage auf einmal zu stellen (andernfalls wird Ihre Frage als zu weit geschlossen). - DavidPostill♦
@Ramhound Wenn Sie meine Kommentare aufmerksam lesen, können Sie sehen, dass ich mich über die Leistung der Powershell beschwere, nicht über .net. .NET wird als Basis von Powershell erwähnt, die schneller funktioniert. Ich bin nicht sicher über die Gesamtanzahl der Dateien, ich versuche das gesamte Laufwerk zu scannen. Also ich schätze da tausende Dateien. - Neir0
@Ramhound berechnete ich: 556458 - Neir0


Antworten:


PowerShell ist ein Programm, das in .Net geschrieben wird, aber es nutzt Schnittstellen zu vielen verschiedenen Interpretern und Laufzeiten, wenn es tatsächlich ausgeführt wird. Es ist eine Shell, also genau wie BASH, obwohl sie in C geschrieben ist, was nichts über die darin ausgeführten Binärdateien und Skripte aussagt. Ausführbare Dateien können .Net-Code, VDM / CMD-Befehle, * Nix-Shell-Befehle, VB / C / WSScript, WMI-Aufrufe, nicht verwaltete API-Schnittstellen, JAR-Dateien oder irgendetwas anderes sein. Diese Optionen beeinflussen die Leistung von Code, der in der Shell ausgeführt wird, und nicht die Sprache, in der die Shell geschrieben ist.

Nun scheint es, als hätten Sie Schwierigkeiten mit der Implementierung eines bestimmten Befehls. Die bessere Frage ist also: Warum? ls langsam zu sortieren, wenn es in PowerShell aufgerufen wird. Wenn wir tiefer graben, finden wir das ls ist ein alias für 'Get-ChildItem', die ein Objektarray zurückgibt, das System.IO.DirectoryInfo-Objekte enthält.

PS C:\Windows\system32> $x=Get-ChildItem ./
PS C:\Windows\system32> $x.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array 

PS C:\Windows\system32> $x[1].GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DirectoryInfo                            System.IO.FileSystemInfo   

PS C:\Windows\system32>

Sie können das abrufen ls Ergebnis, und dann pipe das in eine Sort-Object  Anruf und es wird sich weitgehend so verhalten wie ein IEnumerable.

Beachten Sie, dass IEnumerable nichts für die Leistung tut. Sie können es mit IQueryable verwechseln, das definiert, aber nicht bis zur allerletzten Sekunde eine Abfrage durchführt, vermutlich nachdem es mit Filter- und Sortieroperationen versehen wurde, wie. Net über LinQ zu Objects. Da Get-ChildItem in diesem Fall keine optimierte Abfrage-Engine oder indizierte Datenquelle bietet, können Sie moderne Datenbankoperationen nicht wirklich mit Verzeichnislisten vergleichen.

Versuche also am Ende etwas wie: ls ./ -recurse | Sort-Object Name -descending Wenn ich System32 anvisiere, dauert dies etwa 20 Sekunden, um 54430-Dateien zu verarbeiten und zu sortieren.

Beachten Sie schließlich, dass Sie einen großen Leistungseinbruch erleiden, wenn Sie versuchen, ein Verzeichnis aufzuzählen, auf das Sie nicht persönlich Zugriff haben. Stellen Sie also sicher, dass Sie nicht an Orten verweilen, die Sie nicht betreten dürfen, oder Sie werden eine 2 erleiden + Sekunde warten auf jeden.

Ich hoffe, das hilft.


10
2018-05-13 22:26



IEnumerable bietet keinen Leistungszuwachs, sondern ermöglicht die sofortige Anzeige von Ergebnissen. Auch im Fall von Powershell kann es die Leistung erheblich verbessern, zum Beispiel, wenn "ls" IEnumerable zurückgibt, lädt es nicht alle Dateibaum in den Speicher, was ein großer Overhead sein könnte. - Neir0
Ich habe versucht, ls + sort wie du in deinem Post erwähnt, ich will alle Dateien auf der Festplatte überprüfen, aber es ist unmöglich zu machen, oder ich denke, es könnte ein paar Tage dauern (wirklich, weil ich es in der Nacht verlassen und um Am Morgen gibt es keine Ergebnisse). Aber wenn ich zum Beispiel spezielle Utils für die Überprüfung von Laufwerksraum nehme, arbeiten sie sehr schnell. Das ist mein Punkt. Alles, verschieben, kopieren, suchen arbeitet langsam in Powershell und es ist nervig. - Neir0
Versuchen Sie, die Ausgabe in eine Datei umzuleiten. Ein Standard-Volume-Laufwerk sollte nicht die ganze Nacht dauern, um aufzuzählen. Sind Sie bereits an der Grenze des RAMs oder ist die Festplatte fehlerhaft? - Frank Thomas
Nicht sicher, wahrscheinlich stimmt etwas mit der Festplatte nicht, ich muss zusätzliche Tests machen. Ich habe ein anderes Tool (TreeSize), das ziemlich schnell funktioniert, also ist es nicht so offensichtlich. - Neir0


PowerShell ist so konstruiert, dass es bequem und nicht schnell ist. Es ist ein Kompromiss - es funktioniert hinter den Kulissen, also muss der Benutzer weniger tun. Mehr Arbeit macht es langsamer.

Beachten Sie, dass Ihr PowerShell-Code eine Zeile umfasst, um mehr als Ihr C # -Code in 15 Zeilen zu tun.

Es tut mehr - obwohl Sie das nicht benutzen.

ls Unter Linux gibt String zurück, Strings sind einfach und schnell. Ihr .Net-Code behält nicht einmal den Dateinamen, sondern behält nur die Größe, und die Zahlen sind wieder kleiner noch schneller.

ls in PowerShell, gibt [FileInfo] - und [DirectoryInfo] -Objekte zurück - jedes muss erstellt werden, und jedes muss die Datei abfragen, um die anderen Felder wie CreationTime und LastWriteTime sowie Extension und Length zu füllen, und die Zeitfelder müssen erstellt werden [DateTime] -Objekte.

Das ist viel langsamer für jede Datei. Das kostet andere Optionen, selbst wenn Sie sie nicht verwenden - Ihr PowerShell-Code könnte sich ändern, um die Größe der ersten 10 Dateien zu übernehmen, die im Januar mit einer einfachen Änderung, ohne weitere Cmdlets oder Tools erstellt wurden. der C # -Code müsste umfassend neu geschrieben werden, die Erstellungszeit abfragen, sowohl die Erstellungszeit als auch die Größe zur Sortierung mitnehmen und so weiter.

Der Grund, warum Sie keine Ergebnisse sofort sehen, ist, weil Sie | sort. Das macht es unmöglich. Was passiert, wenn Sie sofort mit der Ausgabe von Ergebnissen beginnen, aber die letzte gefundene Datei nach vorne sortieren muss? Dann wäre die Ausgabe falsch - IEnumerable kann nichts dagegen tun, | sort muss jede Eingabe sammeln, bevor sie etwas ausgeben kann. Deine Sorte ist schneller, weil es kleine Dinge sortiert

Ihr .Net-Code kann die Sortierung selbst schneller durchführen, weil er einen Aufzählungswert von [long] sortiert, er muss keine Eigenschaftensuchen durchführen.

Alles in allem ist Ihr Code viel weniger, und weniger zu tun braucht weniger Zeit. Aber es hat länger gedauert, zu schreiben und ist weniger flexibel und enger fokussiert. Ein Kompromiss.


2
2017-09-23 21:40