Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Optymalizacja kodu. Proste sztuczki.
Forum PHP.pl > Inne > Hydepark
Cezar708
Witam,

Proponuję podzielić się pomysłami na szybkie optymalizacje kodu za pomocą sztuczek:

na początek:
  1. <?php
  2. // do sprawdzania, czy istnieje element w tablicy:
  3. $cars = array( "bmw", "fiat", "volvo", "honda", ... );
  4.  
  5. // zamiast 
  6. if ( in_array('honda', $cars) ){ // ... 
  7.  
  8. // szybciej działa
  9. if ( isset($cars['honda'] ){ // ponieważ isset to nie funkcja tylko konstrukcja języka PHP
  10. ?>


podobnie:
  1. <?php
  2. // zamiast 
  3. if ( strlen( $md5string ) <= 32 ) { //....
  4.  
  5. // szybciej działa:
  6. if ( !isset( $md5string{32} ) ) { // wyjaśnienie jak wyżej
  7. ?>


trochę z innej beczki:
  1. <?php
  2. // zamiast 
  3. include( "skrypt.php" );
  4.  
  5. // szybciej działa
  6. include( "./skrypt.php" ); // ponieważ nie szuka w `include_path`
  7. ?>


lub
  1. <?php
  2. // zamiast 
  3. $i++;
  4.  
  5. // szybciej działa:
  6. ++$i; // ponieważ parser nie tworzy zmiennej tymczasowej
  7. ?>


.. macie jakieś sztuczki, którymi chcecie się podzielić?
kevinsz
Cytat(Cezar708 @ 30.11.2007, 11:09:10 ) *
Witam,

Proponuję podzielić się pomysłami na szybkie optymalizacje kodu za pomocą sztuczek:

na początek:
  1. <?php
  2. // do sprawdzania, czy istnieje element w tablicy:
  3. $cars = array( "bmw", "fiat", "volvo", "honda", ... );
  4.  
  5. // zamiast 
  6. if ( in_array('honda', $cars) ){ // ... 
  7.  
  8. // szybciej działa
  9. if ( isset($cars['honda'] ){ // ponieważ isset to nie funkcja tylko konstrukcja języka PHP
  10. ?>


Zaraz, zaraz... Przecież powyższe konstrukcje sprawdzają coś innego. in_array sprawdza, czy istnieje wartość 'honda' w tablicy $cars, a isset sprawdza czy istnieje element tablicy $cars o kluczu 'honda'. To nie jest to samo winksmiley.jpg

Sam temat uważam za ciekawy, niestety w chwili obecnej nie mam za wiele czasu, aby wprowadzić (i pomyśleć, czy takie mam winksmiley.jpg) własne sztuczki, ale na pewno będę go pilnie śledził smile.gif
Cezar708
Ups... fakt, pospieszyłem się trochę (a miało to być zachęcenie smile.gif )

powinno być:
  1. <?php
  2. $cars = array( "bmw"=>'1', "fiat"=>'12', "volvo"=>'312', "honda"=>'123', ... );
  3. // zamiast 
  4. if ( array_key_exists('honda', $cars) ){ // ... 
  5. // szybciej działa
  6. if ( isset($cars['honda'] ){
  7. ?>


inne przykłady, oczywiście lepiej
  1. <?php
  2. $count = count($arr);
  3. for( $i=0; $i<$count; $i++){//
  4. ?>

zamiast
  1. <?php
  2. for( $i=0; $i<count($arr); $i++){//
  3. ?>


lub
  1. <?php
  2. // lepiej 
  3. switch ( $car ){
  4. case 'honda':
  5. case 'toyota':
  6. case 'suzuki': // o ile suzuki jest japonski tongue.gif tongue.gif tongue.gif
  7. $country = 'japonia';
  8. break;
  9. default:
  10. $country = 'nie japonia';
  11. }
  12.  
  13. // gorzej:
  14. if ( $car == 'honda' || $car == 'toyota' || $car == 'suzuki' ){
  15. $country = 'japonia';
  16. } else {
  17. $country = 'nie japonia';
  18. }
  19. ?>
Jojo
Cytat(Cezar708 @ 30.11.2007, 12:01:52 ) *
  1. <?php
  2. $count = count($arr);
  3. for( $i=0; $i<$count; $i++){//
  4. ?>

We wcześniejszym poście piszesz o używaniu ++$i zamiast $i++, a w tym przykładzie nadal używasz $i++. Trochę konsekwencji winksmiley.jpg
pafka
Cytat(Cezar708 @ 30.11.2007, 12:01:52 ) *
  1. <?php
  2. $count = count($arr);
  3. for( $i=0; $i<$count; $i++){//
  4. ?>


mozesz to zapisac jeszcze krocej smile.gif

  1. <?php
  2. for( $i=0, $count = count($arr); $i<$count; $i++){//
  3. ?>
Cezar708
Cytat(Jojo @ 30.11.2007, 12:09:32 ) *
We wcześniejszym poście piszesz o używaniu ++$i zamiast $i++, a w tym przykładzie nadal używasz $i++. Trochę konsekwencji winksmiley.jpg


Szczerze mówiąc zainteresowało mnie, czy czasem parser sam nie optymalizuje takiej pętli. Okazało się, że tak (z resztą sam sprawdziłem), czyli:
  1. <?php
  2. for( $i=0; $i<$count; $i++){ //.. 
  3. // działa tak samo szybko jak 
  4. for( $i=0; $i<$count; ++$i){ //..
  5. ?>


oczywiście zasada ta nie dotyczy pre- i postinkrementacji w samym kodzie
NetJaro
Cytat(pafka @ 30.11.2007, 12:26:40 ) *
mozesz to zapisac jeszcze krocej smile.gif

  1. <?php
  2. for( $i=0, $count = count($arr); $i<$count; $i++){//
  3. ?>

Tylko tutaj własnie chodzi by obliczać to przed pętlą winksmiley.jpg Wtedy skrypt nie musi za każdym razem używać count.
sticker
  1. <?php
  2. // zamiast 
  3. $i++;
  4.  
  5. // szybciej działa:
  6. ++$i; // ponieważ parser nie tworzy zmiennej tymczasowej
  7. ?>


a skad masz takie informacje? Tak z ciekawości pytam bo nie wydaje mi sie żebyś miał racje, ale nie zagłębiałem sie w działanie parsera php wiec moge sie mylić
Jabol
Cytat(sticker @ 30.11.2007, 18:08:26 ) *
  1. <?php
  2. // zamiast 
  3. $i++;
  4.  
  5. // szybciej działa:
  6. ++$i; // ponieważ parser nie tworzy zmiennej tymczasowej
  7. ?>


a skad masz takie informacje? Tak z ciekawości pytam bo nie wydaje mi sie żebyś miał racje, ale nie zagłębiałem sie w działanie parsera php wiec moge sie mylić

To jest logiczne. Wynika z semantyki powyższych wyrażeń.
sticker
Wcale z tego nie wynika, drzewo budowane jest na podstawie wyrażeń pasujących leksemów napotkanych przez parser w trakcie analizy. To czy jest post czy pre inkrementacja nie zmienia tutaj nic oprócz zapisu w drzewie i żadne tymczasowe zmienne nie są tworzone. Poza tym w każdym z języków programowania obie te operacje odbywają w czasie 1u i są niepodzielne. No wiec dlatego spytałem skąd takie informacje masz pokaż źródło prosze
Kreton
Czyżby temat zaczerpnięty z http://www.jarzebski.pl/read/optymalizacja-php.so ?
nospor
Cytat
Tylko tutaj własnie chodzi by obliczać to przed pętlą winksmiley.jpg Wtedy skrypt nie musi za każdym razem używać count.
To, ze count() jest w for nie znaczy ze jest za kazdym razem wyliczane. Polecam lekture manuala. Wszystko zalezy w ktorym miejscu tego for jest winksmiley.jpg

Cytat
Rownie dobrze mozna powiedziec ze twoj link plagiatuje ten: http://blog.i64.pl/BlogPio/200611/30-optymalizacja-kodu-php/
No, przyznawać sie, kto od kogo bierze? smile.gif
sticker
a ja dodam to smile.gif po to chyba ten wątek był profilowanie
Bastion
@Nospor : do podejrzanych należy dodać :

http://ilia.ws/archives/12-PHP-Optimization-Tricks.html
http://reinholdweber.com/?p=3

i pewnie jeszcze kilkunastu smile.gif bo to tylko wierzchołek góry lodowej Google
pafka
Cytat(NetJaro @ 30.11.2007, 16:45:33 ) *
Tylko tutaj własnie chodzi by obliczać to przed pętlą winksmiley.jpg Wtedy skrypt nie musi za każdym razem używać count.


zwroc uwage ze NIE podalem tego w postaci

  1. <?php
  2. for( $i=0; $i< count($arr); $i++)
  3. ?>


tylko

  1. <?php
  2. for( $i=0, $count = count($arr); $i<$count; $i++)
  3. ?>

gdzie wartosci zmienne $i=0, $count sa wyliczane jeden raz przed rozpoczeciem petli
prgTW
++$i:
miejsce w pamięci najpierw jest inkrementowane a potem jego wartość zwracana

$i++
najpierw tworzona jest kopia zmiennej i celem zapamietania wartości przed inkrementacją, faktyczna zmienna i jest inkrementowana (tracony czas pamiec na stworzenie kopii zmiennej)

$x = ++$i; (doda 1 i zwroci wynik po dodaniu - raz dodaje, raz zwraca)
$x = $i++ (stworzy kopie $i, zwroci jej wartosc do $x, potem dopiero doda 1 - zwiekszy chwilowo zuzycie pamieci i zabierze takt(y) procesora na stworzenie kopii $i);

  1. <?php
  2. for($i = 0, $count = count($arr); $i < $count; ++$i)
  3. ?>

Najkrocej napisane i najbardziej optymalne (a nie chcac nic pominac proponuje rowniez zadeklarowac zmienne $i i $count zebybyly odpowiedniego typu, np. jak $arr ma 200 kluczy to lepiej typ unsigned char niz domyslny int)
phpion
Cytat(prgTW @ 1.12.2007, 16:54:53 ) *
a nie chcac nic pominac proponuje rowniez zadeklarowac zmienne $i i $count zebybyly odpowiedniego typu, np. jak $arr ma 200 kluczy to lepiej typ unsigned char niz domyslny int

W jaki sposób chcesz zrealizować swój pomysł w PHP?
prgTW
Aaa, sorry, siedze i pisze program w c++ i stąd ta pomyłka. PHP ma dynamiczny typ danych, więc sorki smile.gif
Kreton
Cytat
Rownie dobrze mozna powiedziec ze twoj link plagiatuje ten: http://blog.i64.pl/BlogPio/200611/30-optymalizacja-kodu-php/
No, przyznawać sie, kto od kogo bierze?


Ale spójrz, w podanym przeze mnie linku mamy 3 przykłady, które są identyczne jak w tym temacie. smile.gif Co innego w przykładzie, który ty podałeś. biggrin.gif
sticker
Cytat(prgTW @ 1.12.2007, 14:54:53 ) *
++$i:
miejsce w pamięci najpierw jest inkrementowane a potem jego wartość zwracana

$i++
najpierw tworzona jest kopia zmiennej i celem zapamietania wartości przed inkrementacją, faktyczna zmienna i jest inkrementowana (tracony czas pamiec na stworzenie kopii zmiennej)

$x = ++$i; (doda 1 i zwroci wynik po dodaniu - raz dodaje, raz zwraca)
$x = $i++ (stworzy kopie $i, zwroci jej wartosc do $x, potem dopiero doda 1 - zwiekszy chwilowo zuzycie pamieci i zabierze takt(y) procesora na stworzenie kopii $i);

nie no prosze Cie ..... wiesz co to architektura komupterów, prof. Biernat i sumator? podaj fakty dlaczego i gdzie tak napisane.
- jak napisałem te operajce da sie wykonać w 1 takcie cyklu procesora, myle sie ?
- jedyny problem może wynikać z budowy drzewa parsera ale to zaraz na google znajde moze smile.gif
prgTW
  1. <?php
  2. for($k = 0; $k < 5; ++$k){
  3. $count1 = $count2 = 0;
  4. for($j = 0; $j < 1000; ++$j){
  5. $i1 = xdebug_time_index();
  6. for($i = 0; $i < 10000; ++$i){}
  7. $i1 = xdebug_time_index() - $i1;
  8.  
  9. $i2 = xdebug_time_index();
  10. for($i = 0; $i < 10000; $i++){}
  11. $i2 = xdebug_time_index() - $i2;
  12.  
  13. $i1 < $i2 ? ++$count1 : ++$count2;
  14. }
  15. print (string)$count1 . ' - ' . (string)$count2 . "<br />";
  16. }
  17. ?>


$count1 to ilość szybszych preinkrementacji
$count2 to ilość szybszych postinkrementacji

//edit:
xdebug_time_index() to coś jak array_sum(microtime());

//edit2:
oops, byl blad w ilosci iteracji:
Przykładowe wyniki, już poprawne:
751 - 249
742 - 258
752 - 248
766 - 234
754 - 246
sticker
manual php w komentarzach mówi że http://php.oregonstate.edu/manual/en/language.operators.increment.php" title="Zobacz w manualu PHP" target="_manual pre jest szybsza,
pan google mówi że w jezykach po kompilacji nie ma różnicy bo to na poziomie procesora przesunięcie bitowe tylko a w którą strone to juz wsio ryba,

@prgTW to nadal nie wyjaśniało nic tylko eksperyment ja chce faktów :)

edyta mówi
@prgTW czyli widać że nie można przyjąc testów z testów co jest szybsze bo 66-33 % za duży margines


w sumie i tak nie ma co sie kłócić przy milionie operacji to jest zysk 0.1 ms :] czy jakos tak
prgTW
A od kiedy PHP jest językiem kompilowanym?

edit: A czy przesunięcia bitowe to nie są czasem operatory najszybszego mnożenia i dzielenia przez 2, a nie dodawania i odejmowania (inkrementacji i dekrementacji) ?

0.1ms przy milionie wywołań na sekundę moim zdaniem robi różnicę, u mnie widać widoczną różnicę na 10tyś iteracji!
sticker
a czy ja napisałem ze jest? nie wydaje mi się




fakt masz racje.. moj błąd
prgTW
Oczywiście że nie, tylko nie ma sensu pisać o językach kompilowanych jak PHP jest językiem interpretowanym w czasie rzeczywistym. Proces kompilacji jest skomplikowany, często optymalizowany kilka razy, a tutaj mamy do czynienia z ptasim mózgiem generalnie, który wątpię żeby przeprowadzał optymalizację przy wywołaniu, chociaż mogę się mylić, nie jestem współtwórcą php

Co do testów - chciałem tylko pokazać że różnica jest ... i to widoczna ... i to bardzo, więc nikt mi nie wmówi, że postinkrementacja jest równie szybka jak pre, nie chciałem się kłócić, pokój z Tobą smile.gif
sticker
możesz dla testów puścic 100k i dać wyniki czasowe róznicy? to juz tak z ciekawości
prgTW
troche potrwa ale wrzuce te 100k elementarnych iteracji
sticker
oak zrobiłem testa dla 100k
pre - post
0.0509519577026 - 0.0553870201111

nie wiem czy gra warta świeczki, bo rzadko zdarza sie serwis który ma 1000 hitów na sekunde wąskiego gardła trzeba szukać gdzie indziej
prgTW
  1. <?php
  2. for($k = 0; $k < 5; ++$k){
  3. $ratio = 0.0;
  4. for($j = 0; $j < 1000; ++$j){
  5. $i1 = xdebug_time_index();
  6. for($i = 0; $i < 10000; ++$i){}
  7. $i1 = xdebug_time_index() - $i1;
  8.  
  9. $i2 = xdebug_time_index();
  10. for($i = 0; $i < 10000; $i++){}
  11. $i2 = xdebug_time_index() - $i2;
  12.  
  13. $ratio -= $i1;
  14. $ratio += $i2;
  15. }
  16. var_dump($ratio);
  17. }
  18. ?>


Dla 10,000 iteracji i 1,000 pętli (10,000,000 obliczeń)
Wynik na plusie oznacza że postinkrementacja jest wolniejsza (poniższe wartości to różnice czasowe)
float 0.00971746444702
float 0.124341726303
float 0.105871200562
float 0.0391747951508
float 0.0849807262421

//edit:
Dla 100,000 iteracji i 1,000 petli (100,000,000 obliczeń):
float 0.449510574341
float 0.493491411209
float 0.503324985504
float 0.575709104538
float 0.55215716362

Ale sprawdzenie czy liczba jest parzysta bez zatrudniania procesora do wykonywania dzielenia (co jest dla niego najgorszym działaniem chyba) operując na bitach mi się bardzo podoba, o wiele szybsze biggrin.gif

  1. <?php
  2. print $liczba & 1 ? 'nieparzysta' : 'parzysta';
  3. ?>
domis86
Ok. To ja mam dla was zadanie smile.gif
Kto najlepiej zoptymalizuje funkcje my_sort dostanie buzi aaevil.gif

  1. <?php
  2. function my_sort(&$tab)
  3. {
  4. // ******************************************
  5. // mozna tylko zmieniac wnetrze tej funkcji
  6. sort($tab);
  7. }
  8.  
  9.  
  10. $ilosc_testow = 10;
  11. $n = 100000;
  12.  
  13. $time = 0;
  14.  
  15. for ($j=0; $j<$ilosc_testow; ++$j)
  16. {
  17. $tab = array();
  18.  
  19. for($i = 0; $i < $n; ++$i) { $tab[$i] = rand(1,10000); }
  20.  
  21. $delta_time = microtime(TRUE);
  22.  
  23. my_sort($tab);
  24.  
  25. $delta_time = microtime(TRUE) - $delta_time;
  26.  
  27. $time += $delta_time;
  28. }
  29.  
  30. print 'czas: '.(string)$time."<br />";
  31.  
  32. //echo '<pre>'; var_dump($tab); echo '</pre>';
  33. ?>

U mnie to zwraca czas okolo 2.0 sekundy (1.9 do 2.1).
Jakie macie pomysly? smile.gif
Cezar708
hmm zastanowiło mnie to i zrobiłem kilka testów:

Test 1:
  1. <?php
  2. function getMicrotime(){
  3. list($usec, $sec) = explode(" ",microtime());
  4. return ((float)$usec + (float)$sec);
  5. } 
  6. $h=0;
  7. $start = getMicrotime();
  8. for ( $i=0; $i<10000; $i++){
  9. for ( $j=0; $j<10000; $j++){
  10. $h++;
  11. }
  12. }
  13. $wynik = getMicrotime() - $start;
  14. echo "$h++, czas: ".$wynik;
  15. $h=0;
  16. $start = getMicrotime();
  17. for ( $i=0; $i<10000; $i++){
  18. for ( $j=0; $j<10000; $j++){
  19. ++$h;
  20. }
  21. }
  22. $wynik = getMicrotime() - $start;
  23. echo "\n++$h, czas: ".$wynik;
  24. ?>


output:
Kod
$h++, czas: 17.7393829823
++$h, czas: 16.5931489468


Czyli jak widać minimalnie szybszy jest ++$h, (oczywiście testy powtarzałem, wynik relatywnie zawsze był taki sam)

Test2:
  1. <?php
  2. function getMicrotime(){
  3. list($usec, $sec) = explode(" ",microtime());
  4. return ((float)$usec + (float)$sec);
  5. } 
  6. $temp = 0;
  7. $h=0;
  8. $start = getMicrotime();
  9. for ( $i=0; $i<10000; $i++){
  10. for ( $j=0; $j<10000; $j++){
  11. $temp = $h++;
  12. }
  13. }
  14. $wynik = getMicrotime() - $start;
  15. echo "$h++, czas: ".$wynik;
  16. $temp = 0;
  17. $h=0;
  18. $start = getMicrotime();
  19. for ( $i=0; $i<10000; $i++){
  20. for ( $j=0; $j<10000; $j++){
  21. $temp = ++$h;
  22. }
  23. }
  24. $wynik = getMicrotime() - $start;
  25. echo "\n++$h, czas: ".$wynik;
  26. ?>


output:
Kod
$h++, czas: 19.8630981445
++$h, czas: 24.9836299419


czyli ++$h jest zdecydowanie wolniejszy... (oczywiście tu również testy powtarzałem, i wyniki zawsze były relatywnie takie same)

Wniosek,
jeśli robimy zwykłą incrementację to lepiej użyć pre-. Natomiast jeśli przepisujemy to zdecydowanie lepiej $h++. I wiem, że w przypadku post-incrementacji przypisanie jest najpierw (a potem incrementacja), ale to i tak jest w pętli, więc wynik myślę, że nie jest przekłamany. Oczywiście jeśli macie jakieś inne zdanie to proszę o komentarz.

Nie wiem jak Was, ale mnie wyniki zaskoczyły. smile.gif

Jeśli chodzi o spekulacje na temat tego skąd ukradłem ten temat powiem, że szukałem czegoś o takich sztuczkach na tym forum i nie znalazłem. Dlatego zacząłem szukać w googlu. Znalazłem kilka ciekawych, ale chciałbym się dowiedzieć, czy jeszcze jakieś znacie, dlatego rozpocząłem ten temat i nie uważam tego za jakieś przestępstwo.

Pozdrawiam
domis86
Halo? smile.gif Nikt nie da rady zrobic tego sortowania szybciej niz php?
prgTW
  1. <?php
  2. function getMicrotime(){
  3. list($usec, $sec) = explode(" ",microtime());
  4. return ((float)$usec + (float)$sec);
  5. }
  6.  
  7. // i najszybsza wersja jaką znalazłem:
  8. function getMicrotime(){
  9. return strtok(microtime(), ' ') + strtok('');
  10. }
  11. ?>


Poza tym jak nie masz zmiennych w tekście używaj pojedynczych cudzysłowów a nie podwójnych!
DeyV
Cytat
mixed microtime ([ bool $get_as_float ] ) - 5.0.0 The get_as_float parameter was added.


Co oznacza, że w dzisiejszych czasach wystarczy:
  1. <?php
  2. microtime( true );
  3. ?>


@domis86 Metoda optymalizacji tego problemu jest bardzo prosta - należy kupić szybszy komputer (u mnie wykonuje się ten kod w ok sekundę smile.gif )
Jeśli jednak to ci nie odpowiada - możesz skorzystać również z asort () które to wygląda na ok. 30% szybsze.
bartek00
Witam,

Nalezy zwrocic uwage na ograniczona dziedzine wartosci jakie moga znalezc sie w tablicy do posortowania. Mozna wykorzystac count sort i posortowac w czasie liniowym od ilosci elementow. Nie musze wydawac pieniedzy na lepszy komputer.

Pozdrawiam
domis86
<jupi>
W koncu ktos odpowiedzial. Ehh kiepsko cos z waszą optymalizacją smile.gif

buzi dla bartek00
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.