ugrás a tartalomhoz

Tervezési mintákkal teletűzdelt PHP gyorsítása

zottty · 2006. Júl. 13. (Cs), 07.53
Sziasztok!

Egy barátommal régóta fejlszetek egy keretrendszert, ami elég összetett és szét van tervmintázva ( Absztrakt gyárak, összetételek, egykék, ősosztályok MVC-hez ). Ennek az az ára, hogy egy oldal legenerálásához ~20 osztályt kell példányosítani, persze jó sok öröklődéssel.

Az oldal befordítása ~5 másodpercet vesz igénybe egy egész komoly szerveren. Érdekes, de a futási idő 0.5 mp alatt marad. Mögé tettem egy eacceleratort, ez levitte a forditási időt 2 sec-re.

A kérdésem az lenne, hogy mi lehet az oka, hogy ennyire lassú a fordítás és hogyan lehetne ezt gyorsítani.

Annyi még fontos lehet, hogy minden egyes include az __autoload függvényen keresztül valósul meg.

Segítsetek kérlek!

zottty
 
1

Bármi

janoszen · 2006. Júl. 13. (Cs), 09.25
Üdv!

Ha már MVCben fejlesztesz, illene tudnod, hogy ennyiből lehetetlen megmondani. Lehet az adatbázis is, de lehet az objektum modell is.

Pl. ha MySQL/InnoDB-t használsz és foreign keyeket és a foreign key hivatkozik egy mezőre, viszont arra nincs index, akkor az rohadtul belassítja a dolgot. De ugyanúgy lehet, hogy szarul írtátok meg a PHP kódot.

De mondjuk, lehet az is, hogy szarul van fölconfigolva a szerver.

Szóval érted. 20 osztály nem a világ, annyit minden rendes programozó megeszik reggelire, de ha nem jól írtad meg, akkor bizony megeszi a gépet.

Remélem, segített valamit.

J
4

forditás

zottty · 2006. Júl. 13. (Cs), 13.03
Ha már MVCben fejlesztesz, illene tudnod, hogy ennyiből lehetetlen megmondani. Lehet az adatbázis is, de lehet az objektum modell is.


A Fordítás lassú, nem a futás!
5

gondolom

Anonymous · 2006. Júl. 13. (Cs), 17.53
ha megméred minden egyes include beemelési idejét, akkor kiderül hol pihizik a fordító.
6

aha

Hodicska Gergely · 2006. Júl. 13. (Cs), 18.46
Pl. ha MySQL/InnoDB-t használsz és foreign keyeket és a foreign key hivatkozik egy mezőre, viszont arra nincs index, akkor az rohadtul belassítja a dolgot. De ugyanúgy lehet, hogy szarul írtátok meg a PHP kódot.

Hát igen, ez így valóban elég lassú lehet, még szerencse, hogy ilyet nem lehet csinálni:
In the referenced table, there must be an index where the referenced columns are listed as the first columns in the same order.

"Mondjuk ha már MVC-ben fejlesztesz", és mondjuk átgondolod, hogy mire is való egy külső kulcs, akkor a manuál nélkül egy kis józan paraszti ésszel is gyanus lehetne, hogy az említett példának nem sok értelme van.


Felhő
2

re

toxin · 2006. Júl. 13. (Cs), 09.41
http://weblabor.hu/konyvek/phpfejlesztesfelsofokon

tessék levenni a könyvespolcról ;) a könyv igen nagy százalékban csak ezzel foglalkozik
3

Memóriahasználat?

vbence · 2006. Júl. 13. (Cs), 11.19
Ebből következtetni lehetne, hogy az osztályaid terjengősek-e, vagy máshol van a baj...
7

kód nélkül

Hodicska Gergely · 2006. Júl. 14. (P), 00.40
Ennek az az ára, hogy egy oldal legenerálásához ~20 osztályt kell példányosítani, persze jó sok öröklődéssel.

Így látatlanban nehéz megítélni, hogy ez sok vagy kevés, indokolt vagy sem. Egy egyszerű GET kérés kiszolgálásakor is szükség van ezekre?

Ha esetleg mutattok kódot, akkor lehetne többet mondani a tervezésről.

Annyi még fontos lehet, hogy minden egyes include az __autoload függvényen keresztül valósul meg.

Hát ezzel elég sokat lehet ronatni a dolgokon, ha nem jól van megcsinálva. Ha itt mindig filerendszerben kutakodsz, akkor az nem túl ideális. A legjobb, ha egy osztály neve egyből leképezhető egy fájlnévre, ami gondolom a factory-k esetén könnyen megoldható, ezért ezekben az esetekben ajánlott az __autoload mellőzése. Azokkal az alap osztályokkal, amikkel ez nem tehető meg, azt is tehetitek, hogy egy tömbe teszitek a példányosításukhoz szükséges include fájl nevét (a kulcsok az osztálynevek), és ez alapján includeoljátok a szükséges fájlt. Plusz megoldás lehet az alap osztályok egy nagy fájlba másolása, és ennek használata (főleg, ha használtok eaccelerator, akkor nem gond).

Plusz érdemes lenne valami profiler cuccal végigmenni rajta, mert az a 0.5 mp sem kevés sőt.


Felhő
8

____

zottty · 2006. Júl. 14. (P), 12.14
Így látatlanban nehéz megítélni, hogy ez sok vagy kevés, indokolt vagy sem. Egy egyszerű GET kérés kiszolgálásakor is szükség van ezekre?

Szükség sajnos.
Van egy errorhandler, aztán persze van hozzá logger, amit a loggerfactory gyárt, attól függ, mire kell, amit XMLből szed, amit az XML factory gyárt, mert sosem tudhatjuk, milyen XMLkezelő támogatás van az adott rendszeren, aztán akkor már legyen egy Exception-ből származtatott BaseException kivételem, de persze az absztrakt, senki sem dobja, majd példányosít valamit.
Eleve megjön egy DBFactory, aztán az SQLkezelő ösosztályból származtat egy konkrétat, vannak Userek, meg Sessionok, meg minden hozzávaló, változókezelők, és akkor még messze van az MVC, ami persze megint absztrakt, majd mindeki megmondja pontosan mit akar, ehh, meg még ezer dolog...
De a futás tényleg csodás, pikk-pakk < 0.5sec.

De amíg befordítja!!

Az autoloadolás kb így néz ki:

<?php
function __autoload( $moduleName ){
    try {
        switch ( $moduleName ){

            /* DB */
            case "DBFactory":
                loadModule("classes/db/dbfactory.class.php");
                break;;
            case "IAbstractSQL":
                loadModule("classes/db/iabstractsql.interface.php");
                break;;
            case "AbstractSQL":
                loadModule("classes/db/abstractsql.class.php");
                break;;
            case "MySQLConnection":
                loadModule("classes/db/mysqlconnection.class.php");
                break;;
            
            ...
?>
9

Kell a switch?

janoszen · 2006. Júl. 14. (P), 12.57
Nem tudom, szerintem, ennyire nem kellene szétdarabolni az autoloadert. Én annyit csináltam, hogy require_once(); és azzal gyors volt. A sok biztonsági ellenörzés (itt a switch) rányomja a bélyegét az időre.

Szerintem, azt, hogy milyen modult akarsz betölteni, már sokkal előbb le kell ellenőrizni. Hogy ha GET-ben adod meg a modult, állj át "szép" URLekre és adatbázisból szedd a valid URLeket, így kisebb a valószínűsége egy exploitnak és valszeg gyorsabb is lesz.
10

Húha

LeslieNice · 2006. Júl. 14. (P), 13.42
Elöljáróban annyit, hogy én vagyok a akivel zotty fejleszt ezért folyok bele.

Kell a switch?

Ha nincsen switch akkor hogyan mondod meg, hogy melyik esetben mit töltsön be? A többe eset között választani kell. Nem minden mehet regexp-pel ...

Szerintem, azt, hogy milyen modult akarsz betölteni, már sokkal előbb le kell ellenőrizni.

Nem tudom mit jelent nálad a sokkal előbb. Az autoload elveszti a funkcionalitását, ha előre megmondom, hogy melyik modulhoz milyen osztályok szükségesek, mert az azt jelenti, hogy odateszem a file elejére mondjuk include_once-szal.

Ui:
Ne haragudj proclub, de ennek a válaszodnak megint semmi köze a kérdéshez ...
11

Autoloader

LeslieNice · 2006. Júl. 14. (P), 13.48
Valószínűleg a fordítás lassúságáért az autoloader lesz az igazán ludas, hiszen azt nem tudjuk, hogy az autoload-dal betöltött dolgokat mennyire cacheli nekünk az eaccelarator. Sőt így hirtelen úgy gondoljuk, hogy nem is cachelheti, mert az autoloader akkor hívódik meg amikor hibát dob az engine és egy hibára adott választ nem hiszem hogy cacheli. Az esetek döntő többségében viszont autoloadolva vannak az osztályok. Lehet hogy orbitális baromságot írtam, a cache-l kapcsolatban, de az autoloader pontos mechanizmusáról sajnos nem találtunk specifikációt. Ha így van akkor örömmel várom a felvilágosítást!

Viszont az alaposztályok egy file-ba tétele a cache-eléshez jó ötlet azt megnézzük.
12

refactoring

Hodicska Gergely · 2006. Júl. 14. (P), 15.45
amit a loggerfactory gyárt, attól függ, mire kell, amit XMLből szed, amit az XML factory gyárt, mert sosem tudhatjuk, milyen XMLkezelő támogatás van az adott rendszeren

Pl. ezt tipikusan lehetne optimalizálni, bár a fodítási időben ez nem fog sokat számítani. Én nem szeretek ilyesmi adatokat XML-ben tárolni, de az ízlés kérdése, viszont mindenféleképpen érdemes lenne cachelni, mondjuk serializált formában, ha nem túl nagy.

A switch ide szerintem is fölösleges:
isset($classes[$moduleName]) ? loadModule(); : bibiVan();
Amúgy meg switch esetén érdemes a gyakoriság szerint lefele csökkenő sorrendbe redezni a feltételeket. Plusz egy csomó osztályt nem így példányosítanék, hanem a konkrét factoryk névkonvenció alapján ránthatnák be a szükséges fájlokat, tipikusan ilyen lehetne a DB kapcsolat létrehozása stb..

De a futás tényleg csodás, pikk-pakk < 0.5sec.

Ennek még a tizede sem tekinthető igazán gyorsnak, szóval van még ott mit optimalizálni. Gondolj bele, hogy 2-3 kérést tudsz másodpercenként egyszerre kiszolgálni. A túlzott absztrakcióval is csínján kell bánni.


Felhő
13

bizony

Anonymous · 2006. Júl. 14. (P), 20.12
A túlzott absztrakcióval is csínján kell bánni.


Én ezt csak megerősíteni tudom. Bár nem rendelkezem a ZEND motor ilyen mélységű ismeretével, JAVA világban az öröklés egy tipikusan költséges dolog. Tehát könnyen elképzelhető, hogy a sebesség növelésének érdekében kénytelenek lesztek feláldozni az "eleganciából".

A tervezési minták nyakra-főre alkalmazásával kapcsolatban egyébként is vannak fenntartásaim, különösképp PHP környezetben. Ebben a platformban épp az a pláne, hogy gyakorlatilag semmi megkötést nem kényszerít a fejlesztőre, pont ez a varázsa, és épp ezért felesleges JAVA-t csinálni belőle fejlesztés során (itt jegyezném meg: semmi bajom a JAVA-val, imádom).
14

Kösz

zottty · 2006. Júl. 19. (Sze), 01.14
Köszi a válaszokat, haladunk az üggyel, eddig már sikerült futásidőt felezni, de még nincs vége. Még egy kérdés:

Adott egy templateredszer, tipikus faszerkezet pl:
T1, T2, T3 : Template
T1.content = "Hello {valami}";
T1.children = Array("valami" => T2);

T2.content = "{mi}ag";
T2.childern = Array( "mi" => T3" );

T3.content = "ag!";

Ebből lesz a "Helló Világ" gondolom trivi, a kérdésem, hogy van-e valami tapasztalatotok arról, hogy hogyan lehet ezt szépen cache-elni.
Ha valamelyikőtöknek lenne egy átfogó válasza, azt nagyon megköszönném. Igazából a tartalom, szóval a childrenek a legtöbb helyen gyakran változnak...

z

P.s.: Meglepő, de az gyárak, meg az XML elég kevés időt vesz igénybe, gyakorlatilag semennyit.
15

Féligmeddig építő jellegű hozzászólás

vbence · 2006. Júl. 19. (Sze), 07.24
Ha saját template nyelvet készítesz, nem biztos, hogy a php a legjobb amiben ezt megvalósíthatod (gondolok arra, hogy ez már eleve egy interptretált nyelv - efölött még 1 réteget létrehozni, hát...). Próbáld meg inkább php utasításokkal készíteni a template-et. Aki megérti a fenti kódot annak nem lesz bonyolult egykét php utasítás beszúrása sem.

Ami építőbb jellegű: próbáld meg a template-et magát cache-elni úgy, hogy lefordítod phpre. Ha az értelmeződ megvan hozzá, onnan már semmibe sem kerül...

Más: gondolom az XML alatt XSL-re gondoltál. Ha azt használod, akkor minek template?
16

XML

zottty · 2006. Júl. 19. (Sze), 08.50
Nem, XML-re, nem a template-re vonatkozott, ld a korábbi hozzászólásokat

Nemrég megnéztem a smarty cache-elését, fordítását, nekem a Template-et befordítan azért lenne nehéz, mert:

1. egy echo van az egész oldalon, és ez kb a JSP szerű HTTPResponse::sendOutput()
Ez nagyon előnyös pl még nagyon régen készítettem a www.alagastroyal.hu weboldalt és egy rendelést nem csak a képernyőre kellett kiirni, hanem mail-ben is el kellett küldeni, gyakorlatilag így megvan nekem minden szépen faszerkezetben a memóriában és iszonyat könnyű vele ilyen esetekben dolgozni.

2. Ezt a példát nem igazán tudnám echo-san - azaz Template fordítással - megoldani:

<html><body>Az oldal generálása: {gentime} sec
...<futás, iszonyat nagy html kód>...
</body></html>
és a gentime gyereket ugye az lehető legkésőbb kell kitöltenem.

Erre vmi gyors megoldás?
17

Bármit le tudsz fordíani php-re

vbence · 2006. Júl. 19. (Sze), 11.34
A temaplte-ből nem csak echo-s php-t tudsz generálni, hanem mondjuk $s .= '<html>...' tipusut is. Az output bufferingről nem is beszélve, úgyhogy a több output szerintem abszolót megodott.

A "gentime" outbut bufferrel picit bonyolultabb, a $s módszerrel viszont iszonyat egyszerű.

Ezt a "mindent a végén küldünk" kiszolgálási modellt nem nagyon ajánlom, csak ha valami igazán indokolja. Pl szerveroldali XSLT feldolgozás a végén. Főleg hosszan futó php-knél, mert lelassítja a kiszolgálást - az adatok küldése csak a generálás után történik, pedig közben is mehetne.
18

Túlhasznált patternek

Anonymous · 2006. Júl. 20. (Cs), 23.01
Bár már nem egészen ez a téma, az alábbi írást érdemes lehet elolvasni:

http://www.phppatterns.com/docs/design/hello_world_in_patterns

Ez Harry Fuecks klasszikusa, és a lényege, hogy hogyan lehet a legegyszerűbb feladatot (Hello World) a lehető legjobban elbonyolítani.
19

+1 pattern

Bártházi András · 2006. Júl. 20. (Cs), 23.22
Van egy nagyon fontos design pattern: ne bonyolítsd túl a feladatot. Emberek képesek egy 5 oldalból álló oldal mögé betenni egy 100.000 soros keretrendszert, mert hogy az aztán.
20

Occam's razor

Anonymous · 2006. Júl. 20. (Cs), 23.47
Így van. Tulajdonképpen ez a lényege az Occam-borotvája néven elhíresült filozófiának is:

"Nem szabad a dolgokat a szükségesnél bonyolultabban megfogalmazni"

De asszem ennyi elég a filózgatásokból mára ;)
21

KISS

janoszen · 2006. Júl. 21. (P), 08.22
Avagy más néven a KISS filozófia: Keep It Simple Stupid. :D
23

Nem fejlesztésre

vbence · 2006. Júl. 21. (P), 16.33
Ez a megközelítés a fejlesztésre nem használható, ha csak nem akarod a legkisebb változtatás miatt a nulláról kezdve újra megépíteni a projektedet.

Az obektumorientált fejlesztés alapja, hogy a kód egy beláthatatlan távoli jövőre van optimalizálva. A Számalkon pl azt vallották (amivel én ugyan nem értek egyet), hogy ami a feladat leírásában mint főnév szerepel abból mind objektumot kell csinálni. Én eltúlzottnak tartom ezt a megközelítést, de akár működhet is egy valódi OO környezetben, ami optimalizálja az optimalizálni valót.
24

Occam folyt.

Anonymous · 2006. Júl. 21. (P), 17.12
Alighanem félreértettük egymást: itt nem az OO ellen beszélünk, hanem pusztán arról, hogy első sorban mindíg az adott problémát kell megoldani. Egy egyszerű probláéma pedig nem feltétlenül követeli meg a magas szintű - esetleg felesleges - elvonatkoztatást (absztrakciót).

Az Occam féle filozófia arról szól, hogy egy probléma esetében a lehetséges (elvileg helyes) magyarázatok körül az a legjobb, amely esetében a lehető legkevesebb előfeltevést fogalmaztuk meg.

Véleményem szerint ez a hozzáállás a fejlesztésben is megállja a helyét. Semmit sem szabad bonyolultabban csinálni, mint amennyire azt adott probléma megoldása feltétlenül megköveteli.

Végezetül egy idézet a Schlossnagle könyvből:

"[...]A színes négyszögek táblára rajzolásával nincs semmi baj, de eme ragaszkodásunk a bonyolulthoz hatalmas hátrányt jelent. Amikor megtervezünk valmit, arra van szükség, hogy az adott problémára adjunk megoldást. Nem szabad előre tekintenünk, hogy a probléma vajon mi lesz évekkel később, egy nagy méretű, összetett felépítményben, amikor pedig egy általános célú eszközt építünk, nem szabad túlzott konkrétsággal megkötnünk a felhasználó kezét."
25

Azért nem ilyen veszélyes a helyzet

LeslieNice · 2006. Júl. 21. (P), 21.20
Lehet hogy a téma megfogalmazása volt helytelen. A teletűzdelt, nem a legmegfelelőbb szó, az esetünkre. Nem az történt, hogy a legismertebb minták mindegyikét leimplementáltuk, ha kell, ha nem és csak rá erőszakoltuk a feladatra. A factory, az MVC(kisebb módosítással) és az iterator mintákat használtuk ott, ahol nyertünk vele! Más mintákra nem volt szükségünk. Nincsen túlabsztrahálva a dolog, nincsenek felesleges ősosztályok, interfacek.

A lassúság oka azóta már kiderült: a sejtéssel ellentétben nem az autoloader volt a probléma, igaz itt is lehetett egy picit nyerni, de messze nem ez volt a szűk keresztmetszet. A templatekben a helyettesítésekkor a regexpek vitték el csúnyán az időt illetve külső http lekérések maradtak benn egy helyen ahol nem kellett volna. A regexp helyett kihasználva a helyettesítés specialitását, sokat nyertünk.

Ui:
Egy ötoldalas site mögét tényleg hiba lenne betenni, de megnyugtathatlak, hogy nem ötoldalas :)
26

Lehetne konkrétabban?

Balogh Tibor · 2006. Júl. 22. (Szo), 11.45
A regexp helyett kihasználva a helyettesítés specialitását, sokat nyertünk.

Kifejtenéd bővebben!
27

Konkrétabban!

LeslieNice · 2006. Júl. 23. (V), 18.39
A templatejeinkben vannak olyan helyettesítendő részstringek, amelyeket nem minden esetben helyettesítünk. Például ha valaki meg adja az email címét akkor a profile oldal outputjának generálásakor a templateben a %email% részt az email címére cseréltük, ha nem volt email címe akkor egyelőre nem cseréltük üres stringre.

Itt estünk a túlzott általánosság hibájába, hogy ezeket a még bennfelejtett, de az output szempontjából irreleváns részstringeket minden esetben csak az egész output legenerálásakor töröltük ki. Az indok annyi volt, hogy lehetnek olyan helyettesítendő részek, amelyek értéke csak később derül ki. Ez a feltevés részben jogos is, de az esetek döntő többségében nem csak később derül, hogy az adott részstringet ki kell törölni. Ezeket időben kitörölve javítottuk a generálás sebességét.

(A helyettesítés specialitása alatt csak annyit értettem, hogy csak azokkal volt a baj, amelyeket üres stringre kellett helyettesítenünk)
22

Devel gép

janoszen · 2006. Júl. 21. (P), 08.39
Üdv!

Nem tudom, mennyire illhet a Te helyzetedre, de eszembe jutott, hogy nekem a devel gépemen úgyszint iszonyatosan lassan futnak a dolgok. A szerveren viszont tizedmásodperc tört része alatt.

Fogglmam nincs, hogy mitől, talán Linux powa vagy ilyesmi...

J
28

Azt a gépet sose dobd ki,

deejayy · 2011. Júl. 5. (K), 14.41
Azt a gépet sose dobd ki, azon a legjobb perftuningolni! ;]
29

Őőőőő

janoszen · 2011. Júl. 5. (K), 19.24
Őőőőőő azt nézted, hogy mikori a téma?
30

Igen, remélem még megvan! :D

deejayy · 2011. Júl. 5. (K), 19.50
Igen, remélem még megvan! :D