PHP: Wie man ein Hochleistungsskript schreibt
Webagentur » Digitale Nachrichten » PHP: Wie man ein Hochleistungsskript schreibt

PHP: Wie man ein Hochleistungsskript schreibt

PHP ist zwar eine Skript-ähnliche Sprache und wird wegen seiner Langsamkeit kritisiert, aber es bleibt eine der am weitesten verbreiteten Webserver-Sprachen. Im Laufe der Zeit haben die großen Webunternehmen, die PHP verwenden, versucht, die Engine zu optimieren. Die Einführung des Konzepts der Müllsammler in Version 5.3 war ein bemerkenswerter Fortschritt. Aber es gibt viele Möglichkeiten'die Leistung eines Skripts optimieren.

Hauptsächlich im Rahmen der einfachen Seitengenerierung eingesetzt, können diese Optimierungen zwar einen gewissen Gewinn bringen, sind aber für den Nutzer zu wenig sichtbar. Die Optimierung von Datenbanken, Webservern mit Nginx, Engine-Optimierung mit der Einführung von HHVM oder sogar HippyVM ermöglicht es Ihnen, das Rendern Ihrer Seiten einfach zu beschleunigen und die Antwortzeit auf Ihre Anfragen auf einfachere Weise zu optimieren. Trotzdem entwickeln wir manchmal PHP-Skripte mit dem Ziel, schwere Behandlung, oder Webserver können nichts tun.

In diesem Beitrag werde ich detailliert drei Bereiche der Optimierung die ich kürzlich auf ein Skript angewendet habe, das CSV- oder XLS-Dateien verarbeiten musste, die eine große Menge an Informationen enthalten. Die verwendete Speichermenge erreichte ohne Bedenken 1 GB und konnte mehr als 1/2 Stunde dauern.

Bevor ich Ihnen die drei PHP-Konzepte vorstelle, die Ihnen dies ermöglichen könnenAusführungszeit optimieren Beachten Sie neben der Menge an benötigtem Speicher, dass die Algorithmen Ihres Skripts für einen Großteil Ihrer Verarbeitung verantwortlich sind, bevor Sie sich über eine X-Sprache beschweren. C++ mag unendlich schneller sein als PHP, aber wenn Ihre C++-Algorithmen schlecht sind, wird es Ihre Probleme nicht sofort lösen.

Geben Sie seine Variablen frei, begrenzen Sie den Speicherverbrauch

Bevor PHP 5.3 veröffentlicht wurde, war das Problem von PHP das übermäßiger Speicherverbrauch. Außerdem habe ich oft gehört, dass der Speicherverbrauch eines PHP-Skripts niemals reduziert werden könnte… Wenn das eine Zeit lang galt, ist es zum Glück nicht mehr der Fall. Diese Verwaltung verwendet den Begriff Garbage Collector, den wir etwas weiter unten sehen werden.

Eine gute Angewohnheit verloren...

In einigen Sprachen war dies obligatorisch. In PHP ist dieser Begriff völlig vergessen worden! Diese kleine native Funktion unset() ist toein beeindruckendes Dienstprogramm. Sie entspricht der free()-Funktion in C++ und ermöglicht dies freigeben und deshalb von sofort den Speicher freigeben von der Variable verwendet. Die Variable wird vollständig zerstört. Dadurch wird PHP zunächst von ungenutzten Variablen befreit. Dies hat ein weiteres Interesse und hilft uns, unsere Algorithmen besser zu strukturieren. Wenn eine Methode beendet wird, werden die Variablen natürlich automatisch freigegeben, aber Sie werden unten sehen, dass Sie dadurch die Zeit optimieren können, die der "Garbage Collector" mit der Arbeit oder einfach mit seiner Arbeit verbringt, falls er deaktiviert ist . Es gibt also auch ein Geschwindigkeitsgewinn. Und glauben Sie mir, die GC verbraucht eine Menge Ressourcen, um Speicher freizugeben.

Wie ich im vorherigen Absatz sagte, entfernt PHP am Ende einer Funktion oder Methode nicht verwendete Variablen. Aber im Falle eines Skripts, das Massendaten verarbeitet, ist es möglich, dass eine Funktion die anderen verwaltet. Wie in einigen Sprachen werden Sie, wenn es sich um eine Hauptfunktion handelt, wahrscheinlich dazu neigen, Variablen aus der Funktion zurückzuspeichern, bevor Sie sie an andere Funktionen übergeben. Wir können schnell mit einer großen Datenmenge enden. Sobald es nicht mehr gebraucht wird, macht es keinen Sinn, es "herumzuschleppen", wir verteilen es.

Kürzlich, als ich ein Skript schrieb, in dem ich eine ganze Datei mit mehr als 15 MB extrahierte, löschte ich sie, nachdem ich sie verwendet hatte, und ließ es zu Gedächtnis gewinnen !

Den Garbage Collector verstehen

Während meiner Recherche zum Thema Speicherverwaltung stieß ich auf den Artikel eines Kollegen. In diesem etwas in die Jahre gekommenen Artikel erklärt Pascal Martin die Neuheit, die keine mehr ist, den Garbage Collector.

Was ist Garbage Collector?

Für diejenigen, die es nicht kennen oder schon davon gehört haben, aber noch nie die Gelegenheit hatten, es zu benutzen, der Garbage Collector, der auf Französisch mit "Krümelsammler" übersetzt wird, Funktionalität auf niedrigem Niveau das im Intervall X den laufenden Prozess stoppt und einen Scan des vom Skript zugewiesenen Speichers durchführt, um zu erkennen, auf welche Variablen nicht mehr zugegriffen werden kann, um sie zu löschen.

Ich verstehe nicht, früher wurde mir gesagt, dass PHP am Ende einer Methode die Variablen zerstört.
Dies ist nicht ganz richtig. Genauso wie C oder C++ (Elternteil von PHP) wird PHP am Ende einer Methode beendet und verliert die Referenz, die es auf das Objekt hatte. In C existiert nur der Begriff Zeiger, in C++ existieren die Begriffe Zeiger und Referenz nebeneinander.

Sobald die Referenz auf das Objekt verloren gegangen ist und der Garbage Collector gestartet wird, stellt dieser fest, dass die Variable nicht mehr zugänglich ist, und zerstört sie.

Dieses Konzept ist sowohl in JAVA als auch in anderen neueren Sprachen sehr präsent und folglich auf höherem Niveau.

Was hat der Garbage Collector gebracht?

Der GC bot eine beträchtliche Flexibilität bei der Entwicklung. Es ist offensichtlich, dass die Entwicklung in C technischer ist als in Java, PHP oder anderen. Trotzdem werden einige Facetten jetzt vergessen, wie z. B. die Speicherverwaltung, und es ist unser Code, der sich manchmal einfühlt. Wenn dies Flexibilität in unsere Entwicklung brachte, verlangsamte es auch die Ausführung unserer Programme.

Was wir bei diesen Werkzeugen nicht vergessen dürfen, ist, dass wir das Gedächtnis immer auf irgendeine Weise kontrollieren können. Frage des Willens oder der Notwendigkeit …

Schließlich denke ich, dass diese Art von Tools sehr praktisch ist, aber sie können die Anweisungen der Entwickler nicht ersetzen. Ich für meinen Teil finde, dass der C++-Begriff von shared_ptr ist viel interessanter und könnte in Zukunft übergroße Leistungssteigerungen bieten, wenn Zend sich entscheidet, diese Methode in einigen Fällen zu verwenden.

Und in PHP?

Seit PHP 5.3 wurden vier Funktionen hinzugefügt.

  • gc_enable
  • gc_enabled
  • gc_disable
  • gc_collect_cycles
    Ich lasse Ihnen die Muße, die Dokumentation zu lesen, aber um schnell zu sein, sie erlauben Ihnen, den GC zu aktivieren, zu wissen, ob er aktiv ist, ihn zu deaktivieren und die Erfassung manuell zu starten.

Pascal Martin hat in dem Beitrag, den ich oben verlinkt habe, ein Skript veröffentlicht, in dem er einen Batterietest durchführt. Wir können im Testbericht deutlich erkennen, dass die Version ohne GC einen enormen Speicherverbrauch erreicht, sogar ans Limit geht und abstürzt.

Benchmark

Hier ist der ausgeführte Code. Dies wurde dem Blog von Pascal Martin und insbesondere seinem Artikel entnommen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Klasse Knoten {
Öffentlichkeit $parentNode;
Öffentlichkeit $childNodes = Array();
Funktion Knoten() {
$ This->nodeValue = str_repeat('0123456789', 128);
}
}
Funktion Beziehung erstellen() {
$parent= neu Knoten();
$kind = neu Knoten();
$parent->childNodes[] = $child;
$child->parentNode = $parent;
}
for ($ ich = 0; $i 500000; $i++) {
Beziehung erstellen ();
// Dieser Teil wird während des zweiten Tests ausgeführt
if ($optionen[„gc_manual“]) {
gc_collect_cycles();
}
}

Ich führe drei Tests separat durch:

  1. Ich führe diesen Test mit den Basisoptionen durch. Der Garbage Collector ist aktiviert und wird von PHP regelmäßig ausgeführt. Das Skript hat eine Dauer 7.55 Sekunden und der verwendete Speicher erreicht ist 20.98 MB.
  2. Ich führe den gleichen Test durch, indem ich den Garbage Collector deaktiviere und ihn bei jeder Schleifenumdrehung aufrufe. Das Skript dauert 3.79 Sekunden und der verwendete Speicher erreichte seinen Höhepunkt 244.77 Ko.
  3. Ich führe einen dritten Test durch, indem ich den Garbage Collector deaktiviere und niemals manuell sammle. Der Speicher muss also stark aufgefüllt werden. Das Skript dauert 4.46 Sekunden und die Erinnerung ist erreicht Gehe 1.98.

Mit diesem Test können wir die Bedeutung der Speicherverwaltung deutlich erkennen. In unserem auf die Spitze getriebenen Beispiel können wir die Wichtigkeit deutlich erkennen. Einerseits arbeitet der Garbage Collector viel am Speicherverbrauch, aber das wird die Skriptausführung tendenziell verlangsamen. Wir können es sehr gut sehen, wenn wir den 1. Test (mit GC) und den 3. Test ohne Management vergleichen.

Wo unsere Leistungsarbeit geleistet wird, ist Test 2. Keine automatische Speicherverwaltung, manuelle Verwaltung innerhalb dieses Skripts optimiert. Wir schaffen es, die Verarbeitungsgeschwindigkeit um fast das Doppelte zu beschleunigen (7.55 s / 3.79 s = 1.99). Auf diese Weise, Wir haben auch unseren Speicher auf 245 KB begrenzt gegen 21 MB für die automatische Verwaltung. Das ist ein Koeffizient von fast 88 ( (20.98 * 1024) / 244.77 = 87.77).

Konklusion

Obwohl das obige Beispiel die Speicherverwaltung an ihre Grenzen bringt, soll uns dieser Test zeigen, wie viel es sein kann. wichtig, die Speicherverwaltung in unseren Skripten zu studieren. Die Auszahlungen können in einigen Fällen beeindruckend sein. Rechenzeit, Speicher und alles was dazugehört kann eingespart werden.

Referenzen verstehen und anwenden

Wie ich Ihnen bereits etwas früher gesagt habe, implementiert PHP die Variablenübergabe per Referenz, und wie ich Ihnen oben gesagt habe, entspricht diese Art der Übergabe mehr oder weniger der Übergabe per Zeiger.

  • Pass-by-Reference verstehen
  • Zeigerübergabe verstehen
    Dies ist ein wichtiger Teil, nicht nur für PHP, weil dieser Begriff schon lange vorher existierte, sondern auch für die IT. Wenn Sie eine Funktion deklarieren, erfolgt die Passage grundsätzlich durch Kopieren.

    // Öffentliche Kopierfunktion übergeben foo($arg) {…}

    Das impliziert einige Vor- und Nachteile abhängig von Ihrem Code. Das Objekt wird kopiert, was bedeutet, dass der zugewiesene Speicher um das Gewicht des übergebenen Objekts erhöht wird. Das mag lächerlich sein, wenn Sie einen booleschen Wert übergeben, aber es kann viel wichtiger sein, wenn Sie beispielsweise ein Array übergeben.

1
2
3
4
5
6
7
8
9
10
11
Öffentlichkeit Funktion foo() {
$a = 1;
bar($a);
Echo $a; //$a ist 1
}
Öffentlichkeit Funktion Bar($arg) {
$arg = 2;
}

In diesem Fall sehen wir, dass der Wert nicht geändert wurde. Dies kann interessant sein, wenn wir die Variable $a als Basis verwenden und ihren Wert niemals berühren möchten. Wir könnten hier von einem Begriff sprechen, den es in PHP nicht gibt, von einer konstanten Variablen (const).

1
2
3
4
5
6
7
8
9
10
11
12
Öffentlichkeit Funktion foo() {
$a = 1;
$a = bar($a);
Echo $a; //$a ist 2
}
Öffentlichkeit Funktion Bar($arg) {
$arg = 2;
Rückkehr $arg;
}

Ich bin sicher, dass Sie bereits Methoden wie diese geschrieben haben. In diesem Fall handelt es sich eindeutig um einen Fehler. Natürlich ist die Syntax vollkommen richtig, aber für die Kopie des Parameters wurde eine Zuweisung vorgenommen, und die Zuweisung einer Variablen wurde aufgehoben. Teure Speicheraufrufe und unnötige Verarbeitungszeit. Das folgende Formular wäre gleichwertig, aber viel schneller.

1
2
3
4
5
6
7
8
9
10
11
Öffentlichkeit Funktion foo() {
$a = 1;
bar($a);
Echo $a; //$a ist 2
}
Öffentlichkeit Funktion Bar(&$arg) {
$arg = 2;
}

Hier haben wir genau die gleiche Behandlung durchgeführt, aber es ist einfach schneller und weniger aufwendig.

Diese Optimierung ist sehr einfach durchzuführen und kann Ihren Code sogar leichter lesbar machen. Es gibt mehrere Syntaxen, die Sie kennen müssen, um Pass-by-Reference durchzuführen.

  1. Parameterübergabe als Referenz (was wir gerade gesehen haben)
  2. Funktionsrückgabe durch Referenz (hier nicht detailliert, da die PHP-Engine diesen Teil optimiert und ich keinen überzeugenden Gewinn verspürte)
  3. Kopieren einer Variablen per Referenz, nicht sehr nützlich, aber beeindruckend. Ich lasse Sie die PHP-Dokumentation lesen, die sehr detailliert ist. Dinge, die ich ausgelassen habe, könntest du leicht lernen 🙂

Andere Optimierung

Dank der drei oben genannten Optimierungen sollten Sie keine Probleme haben, Ihre Verarbeitung zu beschleunigen. Es gibt jedoch noch andere Artikel. Ich liste Ihnen die interessanten Artikel zu verschiedenen Optimierungen auf, die Sie durchführen können.

  • PHP String Concat vs. Array Implode

Konklusion

Die drei Teile, die ich Ihnen gerade detailliert vorgestellt habe, stellen für meinen Geschmack eine gute Alternative dar, um seine Skripte zu optimieren und Neuentwicklungen in einem zu vermeiden schnellere Sprache als kompilierte Sprache.

Ich habe diese drei Durchgänge an einem meiner Drehbücher gemacht und es ist mir unter anderem gelungen Reduzieren Sie den Speicherverbrauch um 3 ungefähr und einen Geschwindigkeitsgewinn von 2 erreichen.

★ ★ ★ ★ ★