PHP: een krachtig script schrijven
Webbureau » Digitaal nieuws » PHP: een krachtig script schrijven

PHP: een krachtig script schrijven

PHP mag dan wel een scriptachtige taal zijn en bekritiseerd worden omdat het traag is, het blijft een van de meest gebruikte webservertalen. In de loop van de tijd hebben de grote webbedrijven die PHP gebruiken geprobeerd de engine te optimaliseren. De introductie van het concept van Vuilnisman in versie 5.3 was een opmerkelijke vooruitgang. Maar er zijn veel manieren om'optimaliseer de prestaties van een script.

Deze optimalisaties worden voornamelijk gebruikt in het kader van het eenvoudig genereren van pagina's, maar hoewel ze een zekere winst kunnen opleveren, zijn ze niet zichtbaar genoeg voor de gebruiker. Door de optimalisatie van databases, webservers met behulp van Nginx, motoroptimalisatie met de komst van HHVM of zelfs HippyVM kunt u eenvoudig de weergave van uw pagina's versnellen en de tijd van antwoorden op uw vragen op een eenvoudigere manier optimaliseren. Desondanks ontwikkelen we soms PHP-scripts met als doel te maken zware behandeling, of webservers kunnen niets doen.

In dit bericht zal ik in detail treden drie gebieden van optimalisatie die ik onlangs heb toegepast op een script dat CSV- of XLS-bestanden met een grote hoeveelheid informatie moest verwerken. De gebruikte hoeveelheid geheugen bereikte zonder zorgen 1 GB en kon meer dan een half uur duren.

Voordat ik u de drie PHP-begrippen presenteer waarmee u dit kunt doende uitvoeringstijd optimaliseren Naast de hoeveelheid geheugen die in beslag wordt genomen, moet u weten dat voordat u klaagt over een X-taal, de algoritmische structuur van uw script verantwoordelijk is voor een groot deel van uw verwerking. C++ is misschien oneindig veel sneller dan PHP, maar als je C++-algoritmen slecht zijn, lost het je problemen niet meteen op.

Maak de toewijzing van de variabelen ongedaan, beperk het geheugengebruik

Voordat PHP 5.3 werd uitgebracht, was het probleem van PHP de overmatig geheugenverbruik. Bovendien heb ik vaak gehoord dat het geheugenverbruik van een PHP-script nooit te verminderen is… Als dat een tijdje zo was, is het gelukkig niet meer waar. Dit management gebruikt het begrip Garbage Collector dat we verderop zullen zien.

Een goede gewoonte verloren...

In sommige talen was dit verplicht. In PHP is dit begrip volledig vergeten! Deze kleine native functie unset(), is omeen formidabel hulpprogramma. Het is gelijk aan de functie free() in C++ en maakt het mogelijk ongedaan maken en dus van maak het geheugen onmiddellijk vrij gebruikt door de variabele. De variabele is volledig vernietigd. Dit maakt PHP in eerste instantie vrij van ongebruikte variabelen. Dit heeft nog een ander belang en helpt ons om onze algoritmen beter te structureren. Wanneer een methode eindigt, worden de variabelen natuurlijk automatisch ongedaan gemaakt, maar u zult hieronder zien dat u hiermee de tijd kunt optimaliseren die de "vuilnisman" aan het werk besteedt of gewoon zijn werk doet in het geval dat hij is gedeactiveerd. Er is dus ook een winst qua snelheid. En geloof me, de GC verbruikt veel bronnen om geheugen vrij te maken.

Zoals ik in de vorige paragraaf zei, verwijdert PHP aan het einde van een functie of methode ongebruikte variabelen. Maar in het geval van een script dat massagegevens verwerkt, is het mogelijk dat één functie de andere beheert. Zoals in sommige talen, als het een hoofdfunctie is, zult u waarschijnlijk geneigd zijn variabelen uit de functie op te slaan voordat u ze doorgeeft aan andere functies. We kunnen snel eindigen met een grote hoeveelheid gegevens. Zodra het niet meer wordt gebruikt, heeft het geen zin om het te "sjouwen", we maken het ongedaan.

Onlangs, tijdens het schrijven van een script waarin ik een heel bestand aan het uitpakken was dat groter was dan 15 MB, nadat ik het eenmaal had gebruikt, heb ik het verwijderd en toegestaan geheugen winnen !

De vuilnisman begrijpen

Toen ik onderzoek deed naar geheugenbeheer, kwam ik het artikel van een collega tegen. In dit artikel, dat nu een beetje oud is, legt Pascal Martin de nieuwigheid uit die er niet meer is, de Garbage Collector.

Wat is Garbage Collector?

Voor degenen die het niet kennen of er al van hebben gehoord, maar nooit de gelegenheid hebben gehad om het te gebruiken, de Garbage Collector, wat in het Frans wordt vertaald als "kruimel ophalen", functionaliteit op laag niveau die bij interval X het lopende proces stopt en een scan uitvoert van het geheugen dat door het script is toegewezen om te detecteren welke variabelen niet langer toegankelijk zijn om ze te verwijderen.

Ik begrijp het niet, eerder kreeg ik te horen dat aan het einde van een methode PHP de variabelen vernietigt.
Dit is niet helemaal waar. Op dezelfde manier als C of C++ (ouder van PHP), sluit PHP aan het einde van een methode af en verliest het de referentie die het had op het object. In C bestaat alleen de notie pointer, in C++ bestaan ​​de noties pointer en reference naast elkaar.

Zodra de verwijzing naar het object verloren is gegaan en de Garbage Collector eenmaal is gestart, zal deze vaststellen dat de variabele niet langer toegankelijk is en deze vernietigen.

Dit concept is zeer aanwezig in JAVA, evenals in andere, meer recente talen en bijgevolg van een hoger niveau.

Wat heeft de vuilnisman gebracht?

De GC zorgde voor een aanzienlijke ontwikkelingsflexibiliteit. Het is duidelijk dat ontwikkelen in C technischer is dan in Java, PHP of andere. Desondanks worden sommige facetten nu vergeten zoals geheugenbeheer en is het onze code die soms meevoelt. Als dit flexibiliteit bracht in onze ontwikkeling, vertraagde het ook de uitvoering van onze programma's.

Wat we met deze hulpmiddelen niet mogen vergeten, is dat we het geheugen altijd op de een of andere manier kunnen beheersen. Kwestie van willen of noodzaak...

Ten slotte denk ik dat dit soort tools erg praktisch zijn, maar ze kunnen de instructies van de ontwikkelaars niet vervangen. Van mijn kant vind ik dat het C++-begrip van shared_ptr is veel interessanter en zou in de toekomst buitensporige prestatiewinst kunnen opleveren als Zend in sommige gevallen besluit deze methode te gebruiken.

En in PHP?

Sinds PHP 5.3 zijn er vier functies toegevoegd.

  • gc_enable
  • gc_enabled
  • gc_disable
  • gc_collect_cycli
    Ik laat u de vrije tijd om de documentatie te lezen, maar om snel te zijn, kunt u hiermee de GC activeren, weten of deze actief is, deze deactiveren en de verzameling handmatig starten.

Pascal Martin publiceerde in de post die ik hierboven naar je linkte, een script waarin hij een testbatterij uitvoert. We kunnen in het testrapport duidelijk zien dat de versie zonder GC een enorm geheugenverbruik bereikt, zelfs de limiet bereikt en crasht.

criterium

Hier is de uitgevoerde code. Dit is overgenomen uit de blog van Pascal Martin en meer in het bijzonder uit zijn artikel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
klasse Knooppunt {
publiek $ouderNode;
publiek $childNodes = reeks();
functie Knooppunt() {
$ This->nodeValue = str_repeat('0123456789', 128);
}
}
functie relatie creëren() {
$ouder= nieuwe knooppunt();
$ kind = nieuwe knooppunt();
$parent->childNodes[] = $child;
$child->parentNode = $parent;
}
For ($ ik = 0; $ ik 500000; $i++) {
createRelatie();
// Dit deel wordt uitgevoerd tijdens de tweede test
if ($opties["gc_manual"]) {
gc_collect_cycles();
}
}

Ik voer drie tests afzonderlijk uit:

  1. Ik voer deze test uit met de basisopties. De Garbage Collector is ingeschakeld en PHP voert deze regelmatig uit. Het script heeft een looptijd 7.55 secondes en het gebruikte geheugen is bereikt 20.98 MB.
  2. Ik voer dezelfde test uit door de Garbage Collector uit te schakelen en deze bij elke loopbeurt aan te roepen. Het script duurt 3.79 seconden en het gebruikte geheugen piekte op 244.77 KB.
  3. Ik voer een derde test uit door de Garbage Collector uit te schakelen en nooit handmatig te verzamelen. Het geheugen moet dus flink vollopen. Het script duurt 4.46 seconden en het geheugen is bereikt Ga 1.98.

Met deze test kunnen we duidelijk het belang van geheugenbeheer zien. In ons voorbeeld, dat tot het uiterste is doorgevoerd, zien we duidelijk het belang. Aan de ene kant doet de Garbage Collector veel werk aan geheugengebruik, maar dat zal de uitvoering van scripts vertragen. We kunnen het heel goed zien door de 1e proef (met GC) en de 3e proef zonder beheer te vergelijken.

Waar ons uitvoeringswerk wordt gedaan, is op test 2. Geen automatisch geheugenbeheer, handmatig beheer geoptimaliseerd binnen dit script. We slagen erin om de verwerkingssnelheid met bijna twee keer te versnellen (7.55s / 3.79s = 1.99). Op deze manier, we hebben ook ons ​​geheugen beperkt tot 245 KB tegen 21 MB voor automatisch beheer. Dat is een coëfficiënt van bijna 88 ((20.98 * 1024) / 244.77 = 87.77).

Conclusie

Hoewel het bovenstaande voorbeeld geheugenbeheer tot het uiterste drijft, is deze test bedoeld om ons te laten zien hoeveel het kan zijn. belangrijk om geheugenbeheer in onze scripts te bestuderen. De uitbetalingen kunnen in sommige gevallen indrukwekkend zijn. Verwerkingstijd, geheugen en alles wat daarbij hoort kan worden bespaard.

Referenties begrijpen en gebruiken

Zoals ik je eerder al vertelde, implementeert PHP het doorgeven van variabelen door middel van referentie, en zoals ik je hierboven heb verteld, is dit type doorgeven min of meer gelijk aan het doorgeven door middel van een aanwijzer.

  • Pass-by-referentie begrijpen
  • Het passeren van de aanwijzer begrijpen
    Dit is een belangrijk onderdeel, niet alleen voor PHP omdat dit begrip al lang eerder bestond, maar ook voor IT. Kortom, wanneer u een functie declareert, wordt de passage gedaan door te kopiëren.

    // Passeer de openbare kopieerfunctie foo($arg) {...}

    Dat houdt in enkele voor- en nadelen afhankelijk van je code. Het object wordt gekopieerd, wat betekent dat het toegewezen geheugen toeneemt met het gewicht van het doorgegeven object. Dit kan belachelijk zijn als je een boolean doorgeeft, maar het kan veel belangrijker zijn als je bijvoorbeeld een array doorgeeft.

1
2
3
4
5
6
7
8
9
10
11
publiek functie foo() {
$ een = 1;
balk($a);
echo $een; //$a is 1
}
publiek functie bar($arg) {
$arg = 2;
}

In dit geval zien we dat de waarde niet is gewijzigd, dit kan interessant zijn als we de variabele $a als basis gebruiken en de waarde ervan nooit willen aanraken. We zouden hier kunnen spreken van een begrip dat niet bestaat in PHP, van een constante variabele (const).

1
2
3
4
5
6
7
8
9
10
11
12
publiek functie foo() {
$ een = 1;
$a = balk($a);
echo $een; //$a is 2
}
publiek functie bar($arg) {
$arg = 2;
terugkeer $arg;
}

Ik weet zeker dat je al dergelijke methoden hebt geschreven. In dit geval is het duidelijk een vergissing. De syntaxis is natuurlijk volkomen waar, maar er is een toewijzing gemaakt voor de kopie van de parameter en de toewijzing van een variabele is ongedaan gemaakt. Dure geheugenoproepen en onnodige verwerkingstijd. Het onderstaande formulier zou gelijkwaardig zijn, maar veel sneller.

1
2
3
4
5
6
7
8
9
10
11
publiek functie foo() {
$ een = 1;
balk($a);
echo $een; //$a is 2
}
publiek functie bar(&$arg) {
$arg = 2;
}

Hier hebben we precies dezelfde behandeling uitgevoerd, maar het is gewoon sneller en minder verbruikend.

Deze optimalisatie is heel eenvoudig uit te voeren en kan uw code zelfs leesbaarder maken. Er zijn verschillende syntaxis om te weten om pass-by-referentie te doen.

  1. Parameter die door verwijzing wordt doorgegeven (die we net hebben gezien)
  2. Functieteruggave door verwijzing (hier niet gedetailleerd, omdat de PHP-engine dit onderdeel optimaliseert en ik geen overtuigende winst voelde)
  3. Een variabele kopiëren door verwijzing, niet erg handig maar formidabel. Ik heb je de PHP-documentatie laten lezen die uiterst gedetailleerd is. Je zou gemakkelijk dingen kunnen leren die ik heb weggelaten 🙂

Andere optimalisatie

Dankzij de drie bovenstaande optimalisaties zou u geen probleem moeten hebben om uw verwerking te versnellen. Er zijn echter nog andere artikelen. Ik som je de interessante artikelen op over verschillende optimalisaties die je kunt doen.

  • PHP String Concat versus Array Implode

Conclusie

De drie delen die ik u zojuist heb beschreven, vormen naar mijn smaak een goed alternatief om de scripts te optimaliseren en te voorkomen dat de ontwikkelingen in een snellere taal als samengestelde taal.

Ik heb deze drie passen gemaakt op een van mijn scripts en het is me onder andere gelukt verminder het geheugenverbruik met 3 ongeveer en een snelheidswinst behalen met 2.

★ ★ ★ ★ ★