[PHP]Optimalisatie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Goededag,

Voor een project wat enigszins geoptimaliseerd moet worden ging ik op internet op zoek naar optimalisatietechnieken. Na wat dingen te hebben gelezen ging ik zelf eens wat benchmarken en ik kwam het volgende bizarre geval tegen:

for-loop 1:
PHP:
1
2
3
4
5
6
7
8
$timer->start();
//==============START TEST==================//
for($i = sizeof($a); $i <= 0; $i--)
{
    $c[$i] =& $a[$i];
}
//==============STOP TEST==================//
$timer->stop();


for-loop2:
PHP:
1
2
3
4
5
6
7
8
9
$timer->start();
//==============START TEST==================//
$size = sizeof($a);
for($i = 0; $i <= $size; $i++)
{
    $c[$i] =& $a[$i];
}
//==============STOP TEST==================//
$timer->stop();

$a is een 1d array met 1.000.000 elementen.

Executietijd hiervan op een gewone versie van php zonder optimizers of dergelijke:
for1 : 0.00027203559875488
for2 : 1.8486249446869

En het enige significante verschil wat ik hier uit kan halen is het feit dat bij for 1 er 1e6 keer word vergeleken met een constante en bij for-2 er 1e6 keer word vergeleken met een variable.
Vertaal ik dit nu echter naar een while:
PHP:
1
2
3
4
5
6
7
8
9
10
$timer->start();
//==============START TEST==================//
$i = sizeof($a);
while( $i >= 0)
{
    $c[$i] =& $a[$i];
    $i--;
}
//==============STOP TEST==================//
$timer->stop();


Neemt de executietijd plots toch naar 1.17 sec (for2 was 1.90 sec, dus dit is weer net iets beter).

Dit vind ik raar, ligt dit nu aan de "brakke" interpreter/parser van php die slecht optimaliseert, of is er iets wat ik over het hoofd zie waardoor de executietijden logisch te verklaren zijn?


PS: Voor de volledigheid hier de complete code met de bijbehorende uitvoer:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
$timer = new timer();

$a = array();
$c = array();
for ($i=0; $i < 1000000; $i++)
{
    $a[$i] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
}

$timer->start();
//==============START TEST==================//
for($i = sizeof($a); $i <= 0; $i--)
{
    $c[$i] =& $a[$i];
}
//==============STOP TEST==================//
$timer->stop();
echo 'for1 :'.$timer->getTime().'<br />';

//============CLEAR====================/
$timer->clear();
unset($c);
$c = array();
//============/CLEAR====================/

$timer->start();
//==============START TEST==================//
$size = sizeof($a);
for($i = 0; $i <= $size; $i++)
{
    $c[$i] =& $a[$i];
}
//==============STOP TEST==================//
$timer->stop();
echo 'for2 :'.$timer->getTime().'<br />';

//============CLEAR====================/
$timer->clear();
unset($c);
$c = array();
//============/CLEAR====================/

$timer->start();
//==============START TEST==================//
$i = sizeof($a);
while( $i >= 0)
{
    $c[$i] =& $a[$i];
    $i--;
}
//==============STOP TEST==================//
$timer->stop();
echo 'while1 :'.$timer->getTime().'<br />';


code:
1
2
3
for1 :0.00027799606323242
for2 :1.9117231369019
while1 :1.7238299846649

Acties:
  • 0 Henk 'm!

Verwijderd

Met i<=0 loopt die for-loop 1 natuurlijk niet...

Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Ik schaam me dood :( Slotje..

[ Voor 18% gewijzigd door Data-base op 10-06-2007 22:15 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Data-base zou je het nieuwe resultaat van for1-loop erbij willen plaatsen? :)

edit:

leuke interessante php-benchies :)

[ Voor 41% gewijzigd door Verwijderd op 10-06-2007 23:50 ]


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Ja hoor, die eerste for levert nu gemiddeld

1.8932721614838

Dus net een tikje sneller :)
En die site was ik ook tegengekomen ja :)

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Data-base schreef op maandag 11 juni 2007 @ 23:50:
Dus net een tikje sneller :)
En die site was ik ook tegengekomen ja :)
Het enige verschil tussen je for1 en for2 is natuurlijk de volgorde van het aftellen of optellen. Dat is wel heel erg micro-optimaliseren. Het kan zelfs ongewenst gedrag zijn, bovendien is het voor $c benodigde geheugen dan al gealloceerd, dus je hebt kans dat je ook door dat punt verschillen ziet.

't Is veel interessanter en nuttiger om het verschil hiertussen te bekijken:
PHP:
1
2
3
4
5
//for1
for($i = 0; $i < sizeof($a); $i++)

// for2
for($i = 0, $stop = sizeof($a); $i < $stop; $i++)


Dat is iets dat in sommige gecompileerde talen (C, Java?) nauwelijks uitmaakt maar in php vrij significant zal verschillen.

In mijn ervaring helpt het nog altijd meer om de tijd die je in queries stopt te verkleinen dan dit soort mini-dingetjes aan te passen. Wel is het zinvol om te voorkomen dat je onnodig array's en objecten maakt/vult omdat die nogal wat geheugenoverhead hebben en het voorkomen van functiecalls is natuurlijk meestal ook vrij zinvol. En als ik een loop moet gebruiken is dat bij een array met key-value paren vrijwel altijd een foreach, met een array doorgaans een for-loop en met een onbekende hoeveelheid resultaten uit een query een while-loop.

Acties:
  • 0 Henk 'm!

Verwijderd

zucht, verwijder maar.

[ Voor 94% gewijzigd door Verwijderd op 12-06-2007 10:23 . Reden: domheid ]


Acties:
  • 0 Henk 'm!

  • TheBorg
  • Registratie: November 2002
  • Laatst online: 20-09 18:24

TheBorg

Resistance is futile.

Alleen regular expressions kunnen erg gevaarlijk zijn voor de performance. Verder sluit ik me helemaal aan bij ACM.

Acties:
  • 0 Henk 'm!

  • Gwaihir
  • Registratie: December 2002
  • Niet online
Nog zo'n mini-weetje: je kunt nog even ++$i gebruiken ipv $i++. Scheelt ca. 10%, al vist in de meeste productie situaties de Zend Optimizer dat er ook wel uit. (Laatst getest op PHP 5.1.)

[ Voor 8% gewijzigd door Gwaihir op 13-06-2007 16:20 ]


Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Laatste opmerking klopt wel, echter i++ en ++i verschillen wel:

PHP:
1
2
3
4
$i = 1;

if ($i++ == 2) // false
if (++$i == 2) // true


$i++ wordt i verhoogd nadat hij (eventueel) ergens mee vergeleken is, ++$i voordat hij vergeleken wordt.

En ik heb geen flauw idee waarom ++$i sneller is dan $i++.

Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
YopY schreef op woensdag 13 juni 2007 @ 16:30:
Laatste opmerking klopt wel, echter i++ en ++i verschillen wel:
offtopic:
Je voorbeeld klopt niet, bij je tweede vergelijking is $i natuurlijk 3 en derhalve ook false

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

Verwijderd

YopY schreef op woensdag 13 juni 2007 @ 16:30:
En ik heb geen flauw idee waarom ++$i sneller is dan $i++.
Vrij simpel:
code:
1
2
3
4
5
6
7
8
//++$i
$i = $i+1;
return $i;

//$i++
$temp = $i;
$i = $i+1;
return $temp;


Hoewel er nog maar weinig compilers/interpreters zijn die dit niet optimaliseren...

Acties:
  • 0 Henk 'm!

  • Gwaihir
  • Registratie: December 2002
  • Niet online
Ja, mijn opmerking was wel in context bedoeld; je kunt het probleemloos verwisselen wanneer $i++ (danwel $i--) op zichzelf staat, zoals in alle tot dan toe gegeven voorbeelden.

Op het moment dat je gaat vergelijken (zoals in jouw voorbeeld), of toewijzen ($y = $i++) zijn ze niet meer uitwisselbaar. Dan zou ik ook gewoon $i++ gebruiken als me dat uitkomt en me niet druk maken om zo'n stukje micro-optimalisatie.
Pagina: 1