31 Stimmen

Wie kann ich mein Perl-Programm beschleunigen?

Es handelt sich eigentlich um zwei Fragen, aber sie sind sich so ähnlich, dass ich sie der Einfachheit halber einfach zusammenfasse:

  • Erstens : Wenn man ein bestehendes Perl-Projekt hat, welche Möglichkeiten gibt es, es über die reine In-Code-Optimierung hinaus zu beschleunigen?

  • Zweitens : Wenn Sie ein Programm von Grund auf in Perl schreiben, welche Möglichkeiten gibt es, die Leistung erheblich zu verbessern?

Zur ersten Frage: Stellen Sie sich vor, Sie haben ein gut geschriebenes Projekt und müssen die Leistung verbessern, aber Sie können durch Refactoring/Optimierung keine große Verbesserung erzielen. Was würden Sie in diesem Fall tun, um das Projekt zu beschleunigen, außer es in etwas wie C neu zu schreiben?

Bitte halten Sie sich von allgemeinen Optimierungstechniken fern, es sei denn, sie sind Perl-spezifisch .

Ich fragte dies über Python und ich dachte mir, es könnte gut sein, dies auch für andere Sprachen zu tun (ich bin besonders neugierig, ob es Konsequenzen für Psycho et pyrex für Perl).

9voto

MarkR Punkte 60862

Erstellen Sie ein Profil Ihrer Anwendung, z. B. mit dem oben erwähnten Profiler. Dann sehen Sie, wohin die Zeit geht

Wenn die Zeit mit anderen Dingen als der CPU-Nutzung verbracht wird, müssen Sie diese zuerst reduzieren - die CPU ist leicht zu skalieren, andere Dinge nicht.

Einige Vorgänge sind besonders langsam, wie ich festgestellt habe:

  • keys() bei einem großen Hash ist sehr schlecht

  • Verwendung von Data::Dumper für die Fehlersuche. Die Verwendung dieser Funktion bei einer großen Struktur ist sehr langsam. Vermeiden Sie es, wenn Sie können. Wir haben Code gesehen, der das tut:

    use Data::Dumper; 
    $debugstr = Dumper(\%bighash); 
    if ($debugflag_mostlyoff) { log($debugstr); } 
  • Für die meisten Module gibt es Alternativen mit unterschiedlichen Leistungsmerkmalen - einige sind buchstäblich unglaublich schlecht.

  • Einige reguläre Ausdrücke können sehr langsam sein (viele .* usw.) und können durch gleichwertige Ausdrücke ersetzt werden, die schneller sind. Reguläre Ausdrücke lassen sich recht einfach testen (schreiben Sie einfach ein Programm, das sie in einer Schleife gegen einen großen simulierten Datensatz laufen lässt). Die besten regulären Ausdrücke beginnen mit etwas, das sehr schnell getestet werden kann, z. B. mit einer Zeichenkette. Manchmal ist es besser, nicht zuerst nach dem Gesuchten zu suchen, sondern einen "Blick dahinter" zu werfen, um zu prüfen, ob es wirklich das Gesuchte ist. Die Optimierung von Regexps ist wirklich eine schwarze Kunst, in der ich nicht sehr gut bin.

Überlegen Sie nicht, ob Sie etwas in C umschreiben sollen, es sei denn, es ist der letzte Ausweg. Der Aufruf von C aus Perl (oder umgekehrt) hat einen relativ großen Overhead. Wenn Sie eine schnelle Perl-Implementierung bekommen können, ist das besser.

Wenn Sie etwas in C umschreiben, versuchen Sie es so zu tun, dass der Aufruf-Overhead und die Aufrufe an die Perl-Laufzeit minimiert werden (die SV*-Funktionen zum Beispiel kopieren hauptsächlich Strings herum). Eine Möglichkeit, dies zu erreichen, besteht darin, eine C-Funktion zu erstellen, die mehr leistet und weniger oft aufgerufen wird. Das Herumkopieren von Zeichenketten im Speicher ist nicht gut.

Andererseits birgt das Umschreiben in C ein großes Risiko, da man neue Fehlermöglichkeiten einführen kann, z. B. Speicherlecks, Abstürze, Sicherheitsprobleme.

8voto

dland Punkte 4124

Ein sehr lesenswerter Aufsatz zu diesem Thema ist der Vortrag von Nicholas Clark Wenn Perl nicht schnell genug ist (PDF). Einige der Punkte sind etwas veraltet, wie z. B. der Verweis auf Devel::DProf, aber bedenken Sie, dass es 2002 geschrieben wurde.

Dennoch sind viele der behandelten Themen nach wie vor relevant.

8voto

tsee Punkte 4970

Methoden- und Unterroutinenaufrufe sind in Perl nicht frei. Sie sind relativ kostspielig. Wenn sich also bei der Profilerstellung herausstellt, dass Sie einen relativ großen Teil der Laufzeit in kleinen Accessor-Methoden verbringen, könnte das eine Mikro-Optimierung sein, die man sich ansehen sollte.

Was Sie jedoch tun sollten pas do ersetzt hier Accessoren wie get_color():

package Car;
# sub new {...}

sub get_color {
   my $self = shift;
   return $self->{color};
}

package main;
#...
my $color = $car->get_color();

mit kapselungsunterbrechenden Direktzugriffen:

my $color = $car->{color};

Man sollte meinen, dass dies eine Selbstverständlichkeit ist, aber man sieht auch, dass dies überall gemacht wird. Das können Sie tun, indem Sie Klasse::XSAccessor

package Car;
# sub new {...}
use Class::XSAccessor
  getters => {
    get_color => 'color',
  },
  setters => {
    set_color => 'color',
  };

Dadurch entstehen neue Methoden get- und set_color(), die in XS implementiert sind und damit etwa doppelt so schnell sind wie Ihre handgerollte Version. Mutatoren (d.h. "$car->color('red')") sind ebenfalls verfügbar, ebenso wie verkettete Methoden.

Je nach Anwendung kann dies einen sehr kleinen (aber im Grunde kostenlosen) Vorteil bringen. Erwarten Sie nicht mehr als 1-2 %, es sei denn, Sie haben etwas Besonderes vor.

6voto

jrockway Punkte 40754

Der beste Weg, Ihr Programm schneller laufen zu lassen, besteht darin, ihm weniger Arbeit zu machen. Wählen Sie den richtigen Algorithmus für die Aufgabe. Ich habe schon viele langsame Anwendungen gesehen, weil sie einen dummen Algorithmus in einem Bereich des Codes gewählt haben, der Millionen Mal aufgerufen wird. Wenn Sie eine Million * eine Million Operationen statt nur eine Million Operationen durchführen, wird Ihr Programm eine Million Mal langsamer laufen. Buchstäblich.

Hier ist zum Beispiel ein Code, der ein Element in eine sortierte Liste einfügt:

while(my $new_item = <>){
    push @list, $new_item;
    @list = sort @list;
    ... use sorted list
}

Sortierung ist O(n log n). Ein Einfügen in eine sortierte Liste ist O(log n).

Korrigieren Sie den Algorithmus.

1 Stimmen

Die letzte Behauptung, dass das Einfügen in eine sortierte Liste O (log n) ist, ist ungenau, es sei denn, Sie meinen mit "Liste" z. B. einen "Baum".

2voto

Die kostengünstigste Methode könnte sein, schnellere Hardware in Betracht zu ziehen (=> entsprechende Hardwarearchitektur). Ich spreche nicht von schnelleren CPUs, sondern eher von schnelleren Festplatten, schnelleren Netzwerken eigentlich von allem, was die E/A beschleunigt.

Ich habe diese Erfahrung vor vielen Jahren gemacht, als wir eine auf XML-Parsing basierende Anwendung (damals eine Spitzentechnologie<g>) von einem (schnellen und zuverlässigen!) Windows-Server auf eine dedizierte, wenn auch etwas veraltete SUN-Plattform mit schnellerer E/A umzogen.

Wie immer gilt es zu beachten

  • Leistung der Entwickler (wie lange dauert die Programmierung, wie komplex ist das Problem, ist das Ergebnis wartbar),
  • Leistung der Hardware,
  • Leistung der Software

und dort zu verbessern, wo es für das jeweilige Problem am effektivsten (kostenmäßig!) ist...

0 Stimmen

Mir gefällt diese Idee, aber es sollte gesagt werden, dass manchmal ein wenig mehr anfängliche Entwicklungszeit auf lange Sicht zu weitaus geringeren Hardwarekosten/schnelleren Ergebnissen führen kann. Es hängt wirklich davon ab, wie lange das Projekt laufen soll.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X