PHP: kaip parašyti didelio našumo scenarijų
Interneto agentūra » Skaitmeninės naujienos » PHP: kaip parašyti didelio našumo scenarijų

PHP: kaip parašyti didelio našumo scenarijų

PHP gali būti į scenarijus panaši kalba ir kritikuojamas dėl lėtumo, tačiau ji išlieka viena iš plačiausiai naudojamų žiniatinklio serverio kalbų. Laikui bėgant, pagrindinės interneto įmonės, kurios naudoja PHP, siekė optimizuoti variklį. Sąvokos įvedimas Šiukšlių surinkėjas 5.3 versijoje buvo pastebimas pažanga. Tačiau yra daug būdų'optimizuoti scenarijaus našumą.

Šie optimizavimai dažniausiai naudojami paprasto puslapio generavimo rėmuose, nors ir gali duoti tam tikrą naudą, tačiau vartotojui nėra pakankamai matomi. Duomenų bazių, žiniatinklio serverių optimizavimas naudojant Nginx, variklio optimizavimas, atsiradus HHVM ar net HippyVM, leis jums tiesiog pagreitinti puslapių atvaizdavimą ir optimizuoti atsakymų į jūsų užklausas laiką paprasčiau. Nepaisant to, kartais kuriame PHP scenarijus siekdami sukurti sunkus gydymas, arba žiniatinklio serveriai nieko negali padaryti.

Šiame įraše išsamiai aprašysiu trys optimizavimo sritys kurį neseniai pritaikiau scenarijui, kuris turėjo apdoroti CSV arba XLS failus, kuriuose yra daug informacijos. Naudojamos atminties kiekis be rūpesčių pasiekė 1 GB ir galėjo veikti daugiau nei 1/2 valandos.

Prieš pateikdamas jums tris PHP sąvokas, kurios jums gali leistioptimizuoti vykdymo laiką ir užimtos atminties kiekį, žinokite, kad prieš skųsdamiesi dėl X kalbos, jūsų scenarijaus algoritmas yra atsakingas už didelę jūsų apdorojimo dalį. C++ gali būti be galo greitesnis nei PHP, bet jei jūsų C++ algoritmai yra blogi, tai iš karto neišspręs jūsų problemų.

Paskirstykite jo kintamuosius, apribokite atminties suvartojimą

Prieš išleidžiant PHP 5.3, PHP problema buvo per didelis atminties suvartojimas. Be to, dažnai girdėjau, kad PHP scenarijaus atminties sąnaudos niekada negalėjo būti sumažintos... Jei kurį laiką tai buvo tiesa, tai, laimei, jau nebetiesa. Ši vadovybė naudoja šiukšlių surinkėjo sąvoką, kurią matysime šiek tiek toliau.

Prarastas geras įprotis...

Kai kuriomis kalbomis tai buvo privaloma. PHP ši sąvoka buvo visiškai pamiršta! Ši maža savoji funkcija unset(), yra todidžiulis naudingumas. Tai lygiavertė funkcijai free () C++ ir leidžia paskirstyti ir todėl iš karto atlaisvinkite atmintį naudojamas kintamasis. Kintamasis yra visiškai sunaikintas. Tai iš pradžių atlaisvina PHP nuo nenaudojamų kintamųjų. Tai turi dar vieną interesą, padedantį geriau struktūrizuoti savo algoritmus. Žinoma, metodui pasibaigus, kintamieji automatiškai išskirstomi, bet toliau pamatysite, kad tai leidžia optimizuoti laiką, kurį „šiukšlių surinkėjas“ praleidžia dirbdamas arba tiesiog atlikdamas savo darbą, jei jis būtų išjungtas. Todėl taip pat yra greičio padidėjimas. Ir patikėkite manimi, GC sunaudoja daug išteklių, kad atlaisvintų atmintį.

Kaip sakiau ankstesnėje pastraipoje, funkcijos ar metodo pabaigoje PHP pašalina nenaudojamus kintamuosius. Tačiau jei scenarijus apdoroja masinius duomenis, viena funkcija gali administruoti kitas. Kaip ir kai kuriomis kalbomis, jei tai pagrindinė funkcija, tikriausiai būsite linkę išsaugoti funkcijos kintamuosius prieš perduodant juos kitoms funkcijoms. Greitai galime gauti didelį duomenų kiekį. Kai tik jis nebenaudojamas, nėra prasmės jo „vežtis“, mes jį paskirstome.

Neseniai rašydamas scenarijų, kuriame išgavau visą didesnį nei 15 MB failą, jį panaudojęs ištryniau ir leidau įgyti atmintį !

Supratimas apie šiukšlių surinkėją

Tyrinėdamas atminties valdymą aptikau kolegos straipsnį. Šiame straipsnyje, kuris dabar yra šiek tiek senas, Pascalis Martinas paaiškina naujovę, kurios nebėra – šiukšlių surinkėją.

Kas yra šiukšlių surinkėjas?

Tiems, kurie apie tai nežino arba jau girdėjo, bet niekada neturėjo galimybės juo naudotis, šiukšlių surinkėjas, kuris išvertus iš prancūzų kalbos yra „trupinių surinkėjas“, žemo lygio funkcionalumas kuris intervalu X sustabdo vykdomą procesą ir atlieka scenarijaus skirtos atminties nuskaitymą, kad nustatytų, kurie kintamieji nebepasiekiami ir juos ištrinti.

Nesuprantu, anksčiau man buvo pasakyta, kad metodo pabaigoje PHP sunaikina kintamuosius.
Tai nėra visiškai tiesa. Lygiai taip pat kaip C arba C++ (pagrindinis PHP), metodo pabaigoje PHP išeina ir praranda nuorodą, kurią turėjo objekte. C kalboje egzistuoja tik rodyklės sąvoka, C++ – rodyklės ir atskaitos sąvokos.

Praradus nuorodą į objektą ir paleidus šiukšlių rinktuvą, pastarasis nustatys, kad kintamasis nebepasiekiamas, ir jį sunaikins.

Ši sąvoka labai paplitusi JAVA ir kitose naujesnėse kalbose, taigi ir aukštesnio lygio.

Ką atnešė šiukšlių surinkėjas?

GC suteikė didelį plėtros lankstumą. Akivaizdu, kad kurti C yra labiau techninė, nei Java, PHP ar kt. Nepaisant to, kai kurie aspektai dabar yra pamiršti, pavyzdžiui, atminties valdymas, o mūsų kodas kartais užjaučia. Jei tai suteikė lankstumo mūsų plėtrai, tai taip pat sulėtino mūsų programų vykdymą.

Naudodamiesi šiais įrankiais neturime pamiršti, kad visada galime kažkaip valdyti atmintį. Noros ar būtinybės klausimas...

Galiausiai, manau, kad tokio tipo įrankiai yra labai praktiški, tačiau jie negali pakeisti kūrėjų nurodymų. Savo ruožtu manau, kad C++ sąvoka shared_ptr yra daug įdomesnis ir gali pasiūlyti didesnį našumo padidėjimą ateityje, jei Zend nuspręs kai kuriais atvejais naudoti šį metodą.

O PHP?

Nuo PHP 5.3 buvo pridėtos keturios funkcijos.

  • gc_enable
  • gc_enabled
  • gc_disable
  • gc_collect_cycles
    Palieku jums laisvalaikį skaityti dokumentaciją, bet, kad būtų greičiau, jie leidžia aktyvuoti GC, žinoti, ar jis aktyvus, išjungti ir rankiniu būdu pradėti rinkti.

Pascalis Martinas paskelbė įraše, kurį su jumis susiejau aukščiau, scenarijų, kuriame jis atlieka bandomąjį akumuliatorių. Testo ataskaitoje aiškiai matome, kad versija be GC pasiekia milžiniškas atminties sąnaudas, net pasiekia ribą ir stringa.

etalonas

Čia yra įvykdytas kodas. Tai buvo paimta iš Pascal Martin tinklaraščio ir ypač iš jo straipsnio.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
klasė mazgas {
visuomenės $parentNode;
visuomenės $childNodes = masyvas();
funkcija mazgas() {
$ tai->nodeValue = str_repeat(„0123456789“, 128);
}
}
funkcija sukurti Santykį() {
$parent= Naujas produktas mazgas ();
$vaikas = Naujas produktas mazgas ();
$parent->childNodes[] = $vaikas;
$vaikas->parentMazgas = $parent;
}
forumas ($i = 0; $i 500000; $i++) {
sukurtiRelationship();
// Ši dalis vykdoma antrojo bandymo metu
if ($options[„gc_manual“]) {
gc_collect_cycles();
}
}

Atlieku tris testus atskirai:

  1. Atlieku šį testą su pagrindinėmis parinktimis. Šiukšlių surinkėjas įjungtas, o PHP jį paleidžia reguliariai. Scenarijus turi trukmę 7.55 secondes ir naudojama atmintis pasiekė 20.98 Pr.
  2. Atlieku tą patį testą, išjungdamas šiukšlių rinktuvą ir iškviesdamas jį kiekviename kilpos posūkyje. Scenarijus trunka 3.79 sekundės ir naudojama atmintis pasiekė aukščiausią tašką 244.77 KB.
  3. Atlieku trečią bandymą išjungdamas šiukšlių rinktuvą ir niekada nerinkdamas rankiniu būdu. Todėl atmintis turi būti stipriai užpildyta. Scenarijus trunka 4.46 sekundės ir atmintis pasiekė 1.98 Eiti.

Atlikę šį testą aiškiai matome atminties valdymo svarbą. Mūsų pavyzdyje, kuris nukeliamas į kraštutinumą, aiškiai matome svarbą. Viena vertus, šiukšlių surinkėjas daug dirba su atminties suvartojimu, tačiau tai gali sulėtinti scenarijaus vykdymą. Tai labai gerai matome palyginę 1-ąjį testą (su GC) ir 3-ią testą be valdymo.

Mūsų našumo darbas yra 2 bandymas. Nėra automatinio atminties valdymo, rankinis valdymas optimizuotas šiame scenarijuje. Apdorojimo greitį mums pavyksta paspartinti beveik du kartus (7.55 s / 3.79 s = 1.99). Šiuo būdu, taip pat apribojome savo atmintį iki 245 KB prieš 21 MB automatiniam valdymui. Tai yra beveik 88 (20.98 * 1024) / 244.77 = 87.77 koeficientas.

Išvada

Nors aukščiau pateiktame pavyzdyje atminties valdymas yra ribotas, šis testas skirtas mums parodyti, kiek jis gali būti. svarbu ištirti atminties valdymą mūsų scenarijuose. Kai kuriais atvejais išmokos gali būti įspūdingos. Galima sutaupyti apdorojimo laiką, atmintį ir viską, kas su ja susijusi.

Suprasti ir naudoti nuorodas

Kaip jau sakiau šiek tiek anksčiau, PHP įgyvendina kintamųjų perdavimą pagal nuorodą, ir, kaip jau sakiau aukščiau, šio tipo perdavimas yra daugiau ar mažiau lygiavertis perdavimui žymekliu.

  • Perėjimo nuorodos supratimas
  • Žymeklio perdavimo supratimas
    Tai svarbi dalis ne tik PHP, nes ši sąvoka egzistavo jau seniai, bet ir IT. Iš esmės, kai deklaruojate funkciją, ištrauka atliekama kopijuojant.

    // Praleisti viešo kopijavimo funkciją foo($arg) {…}

    Tai reiškia kai kurie pliusai ir minusai priklausomai nuo jūsų kodo. Objektas nukopijuojamas, o tai reiškia, kad skirta atmintis padidės perduoto objekto svoriu. Tai gali būti juokinga, jei praleidžiate loginį, bet tai gali būti daug svarbiau, jei, pavyzdžiui, perduodate masyvą.

1
2
3
4
5
6
7
8
9
10
11
visuomenės funkcija foo() {
$a = 1;
baras($a);
praleisti $a; //$a yra 1
}
visuomenės funkcija baras($arg) {
$arg = 2;
}

Šiuo atveju matome, kad reikšmė nebuvo pakeista, tai gali būti įdomu, jei naudosime kintamąjį $a kaip pagrindą ir niekada nenorime liesti jo reikšmės. Čia galėtume kalbėti apie sąvoką, kurios PHP neegzistuoja, apie pastovų kintamąjį (const).

1
2
3
4
5
6
7
8
9
10
11
12
visuomenės funkcija foo() {
$a = 1;
$a = baras($a);
praleisti $a; //$a yra 2
}
visuomenės funkcija baras($arg) {
$arg = 2;
grįžti $arg;
}

Esu tikras, kad jau esate parašę tokius metodus. Šiuo atveju tai akivaizdžiai klaida. Žinoma, sintaksė yra visiškai teisinga, tačiau parametro kopijai buvo skirta paskirstymas ir kintamojo atskyrimas. Brangūs atminties skambučiai ir nereikalingas apdorojimo laikas. Žemiau pateikta forma būtų lygiavertė, bet daug greitesnė.

1
2
3
4
5
6
7
8
9
10
11
visuomenės funkcija foo() {
$a = 1;
baras($a);
praleisti $a; //$a yra 2
}
visuomenės funkcija baras(&$arg) {
$arg = 2;
}

Čia mes atlikome lygiai tą patį apdorojimą, bet jis yra tiesiog greitesnis ir mažiau sunaudoja.

Šis optimizavimas yra labai paprastas ir netgi gali palengvinti kodo skaitymą. Yra keletas sintaksių, kurias reikia žinoti, kad būtų galima atlikti trumpą nuorodą.

  1. Parametras perduodamas pagal nuorodą (ką ką tik pamatėme)
  2. Funkcijos grąžinimas pagal nuorodą (čia nedetalizuosi, nes PHP variklis optimizuoja šią dalį ir aš nepajutau jokio įtikinamo pelno)
  3. Kintamojo kopijavimas pagal nuorodą, nėra labai naudingas, bet didžiulis. Leidžiau jums perskaityti PHP dokumentaciją, kuri yra labai išsami. Galite lengvai išmokti dalykų, kuriuos praleidau 🙂

Kitas optimizavimas

Dėl trijų aukščiau pateiktų optimizacijų jums neturėtų kilti problemų paspartinti apdorojimą. Tačiau yra ir kitų dalykų. Pateikiu jums įdomių straipsnių apie įvairius optimizavimus, kuriuos galite atlikti.

  • PHP String Concat vs Array Implode

Išvada

Trys dalys, kurias ką tik jums paaiškinau, yra gera alternatyva mano skoniui optimizuoti scenarijus ir išvengti naujo paleidimo greitesnė kalba kaip kompiliuota kalba.

Aš padariau šiuos tris leidimus pagal vieną iš savo scenarijų ir, be kita ko, man tai pavyko sumažinti atminties suvartojimą 3 apytiksliai ir padidinti greitį 2.

★ ★ ★ ★ ★