Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Obliczanie czasu sortowania
Forum PHP.pl > Forum > Przedszkole
Shlizer
Witam..
mam taki mało spotykany problem (google nie dał rady =/).. otóż tworzę sobie tabelkę różnych metod sortowania tablic (bąbelkowe, quick, wstawianie itd.) i chcę obliczyć czas posortowania rosnąco, losowo i malejąco dla próby 1k, 10k i 100k liczb. Wszystko wychodzi ładnie pięknie, tzn. skrypt dla każdej komórki tworzy odpowiednio dużą tablicę i odpowiednio ją wypełnia liczbami. Następnie sprawdzany jest microtime, dokonywane sortowanie i obliczana różnica microtime na końcu.

Wyniki są jednak nader dziwne, bo wg przedstawionych obliczeń tablice z 1k elementów sortują się o kilka ms dłużej niż tablice 10k (dalej, tj. porównując 10k i 100k jest odwrotnie, ale to akurat nic dziwnego, że większą tablicę sortuje dłużej).

Jedyny pomysł, jaki przychodzi mi na myśl to to, że PHP tworzy sobie cache interpretera (istnieje taki wbudowany w standardowy php? 0o), ale czuję, że ta opcja odpada, bo porównując liczby przy każdym odświeżeniu zwykle nie są identyczne.

Ostatnia rzecz (choć nie wydaje mi się, żeby miała tu znaczenie) - funkcje sortowania ładowane są z zewnętrznych plików (oddzieliłem logikę samego sortowania od tworzenia tablic testowych i obliczeń czasowych).

Skąd rodzi się moje pytanie - czy byłby ktoś w stanie wyjaśnić mi te dziwne anomalie w czasach sortowania tablic?
nospor
A moze poprostu źle mierzysz czas? wink.gif
Crozin
1. Pokaż swój kod.
2. Średnią z ilu sortowań wybierasz?
Shlizer
  1. (...)
  2. public function getTime() {
  3. $time = -microtime(true) *1000 *1000;
  4.  
  5. $this->mySort($this->a); // tabela jest pobierana do klasy wcześniej i znajduje się w zmiennej $a
  6. // natomiast funkcja mySort odpowiada za sortowanie w określony sposób
  7. $time += microtime(true) *1000 *1000;
  8. return number_format($time, 0, '.', '');
  9. }
  10. (...)

W ten sposób uzyskuję różnicę czasu sprzed i po sortowaniu w milisekundach. Sprawdzałem także różnice w mikrosekundach, bez formatowania liczby (myślałem, że to problem z zaokrąglaniem), ale ciągle występuje ten sam błąd - tablica z mniejszą ilością elementów (tak, count'owałem je, a nawet var_dumpowałem i pobieżnie przeglądałem ich ilość i wartości) sortowana jest wg powyższego skryptu wolniej niż jej odpowiednik o rząd, dwa rzędy większy..

Cytat(Crozin @ 22.04.2014, 15:03:35 ) *
1. Pokaż swój kod.
2. Średnią z ilu sortowań wybierasz?

1. Jak powyżej.. mogę wrzucić całość, ale ciut tego będzie - wszystko odbywa się przez ajax (wciskam przycisk i symetrycznie odpytuję serwer, wypełniając pola tabeli).. jednak odpytywanie bez tej technologii (wpisując po prostu w URL z GETem) daje takie same wyniki.
2. Być może to trochę naprowadzi na właściwy tor, ale walnąłem funkcję sortowania w pętli i zauważyłem, że mniejsze tablice sortuje szybciej. Tj. dla wbudowanego w php quicksorta 1000 pętli tablicy rosnącej wykonuje się 661ms (1k pól w tablicy), 651ms (10k), 442ms (100k).. 0o
Crozin
Pokaż SSCCE, z którym przynajmniej u Ciebie występuje "błąd". Sam stworzyłem bardzo prosty test:
  1. <?php
  2.  
  3. function randomArray($count) {
  4. $arr = array();
  5.  
  6. for ($i = 0; $i < $count; $i++) {
  7. $arr[] = mt_rand();
  8. }
  9.  
  10. return $arr;
  11. }
  12.  
  13. $arr = randomArray(1000);
  14. $time = -microtime(true) *1000 *1000;
  15. sort($arr);
  16. $time += microtime(true) *1000 *1000;
  17. echo number_format($time, 0, '.', '') . PHP_EOL;
  18.  
  19. $arr = randomArray(10000);
  20. $time = -microtime(true) *1000 *1000;
  21. sort($arr);
  22. $time += microtime(true) *1000 *1000;
  23. echo number_format($time, 0, '.', '') . PHP_EOL;
  24.  
  25. $arr = randomArray(1000);
  26. $start = microtime(true);
  27. sort($arr);
  28. $elapsedTime = microtime(true) - $start;
  29. echo $elapsedTime . PHP_EOL;
  30.  
  31. $arr = randomArray(10000);
  32. $start = microtime(true);
  33. sort($arr);
  34. $elapsedTime = microtime(true) - $start;
  35. echo $elapsedTime . PHP_EOL;
Wyniki za każdym razem są "odpowiednie", tj. mniejsza tablica sortuje się odpowiednio szybciej (rząd wielkości).
Shlizer
No dobrze.. więc jak wspomniałem mój skrypt ładowany jest dynamicznie przez Ajax do tabelki. Ładuję go sychronicznie, przez co każde kolejne sortowanie nie zamula serwera i - przynajmniej mam nadzieję - eliminuję częściowo fałszowanie wyników. Sam skrypt myślę, że jest poprawny (a przynajmniej to nie tu tkwi problem), bo przy wysyłaniu GETem w URLu z palca wpisanych wartości wyniki są takie same.

Do skryptu wysyłam 3 zmienne: type, będący określeniem rodzaju sortowania (dla prostoty tutaj dodam tylko wbudowany qsort), sort, mówiący w jaki sposób będzie wstępnie posortowana tablica testowa (inc - rosnąco, rnd - losowo, dec - malejąco) oraz val, czyli ilość tysięcy pól w tablicy. Tak wygląda plik, który otrzymuje te dane (na samym dole przykład online):

  1. $type = htmlspecialchars($_GET['type']);
  2. $sort = htmlspecialchars($_GET['sort']);
  3. $val = (int)htmlspecialchars($_GET['val']);
  4.  
  5. if ($val <= 0) die('err'); // dla sprawdzenia, czy aby na pewno będzie co liczyć w tabeli testowej
  6.  
  7. $val *= 1000;
  8. $arr = array();
  9. $min = 0;
  10. $max = $val;
  11.  
  12. switch($sort) { // tworzymy odpowiednią tabelę testową
  13. case 'inc':
  14. for ($i=0; $i<$val; $i++)
  15. $arr[$i] = $i;
  16. break;
  17. case 'rnd':
  18. for ($i=0; $i<$val; $i++)
  19. $arr[$i] = mt_rand($min, $max);
  20. break;
  21. case 'dec':
  22. for ($i=$val-1; $i>=0; $i--)
  23. $arr[$i] = $i;
  24. break;
  25. default: die('err');
  26. }
  27. $file = 'sort/'.$type.'.php';
  28.  
  29. if (file_exists($file)) { // ładujemy plik ze skryptem do sortowania
  30. require_once($file);
  31. $sort = new SortTest($arr);
  32. die($sort->start().' ms');
  33. }
  34. else
  35. die('err');


Plik do sortowania znajduje się, jak pisałem, w osobnym pliku i wygląda następująco:
  1. class SortTest {
  2. private $a = array();
  3.  
  4. public function __constructor($array) {
  5. $this->a = $array;
  6. }
  7.  
  8. public function start() {
  9. $time = -microtime(true) *1000 *1000;
  10.  
  11. for ($i=0; $i<1000; $i++) // pętla for, w celu 'uwypuklenia' dziwnych czasów wykonywania sortowań
  12. $this->mySort($this->a);
  13.  
  14. $time += microtime(true) *1000 *1000;
  15. return number_format($time, 1, '.', ''); // formatujemy ms z jednym przecinkiem (sprawdzenie, czy nie ma błędu przy zaokrąglaniu przy mniejszych liczbach)
  16. }
  17.  
  18. public function mySort($a) {
  19. sort($a);
  20. }
  21. }


Po przepisaniu tego w przykład online wygląda tak: http://ideone.com/Z4tTUV (wyniki mogą być trochę zakłamane ze względu na to, że nie wiem jak wygląda środowisko na którym to jest uruchamiane, ale tego rodzaju rozrzut obliczeń mam właśnie u siebie)
nospor
for ($i=0; $i<1000; $i++) // pętla for, w celu 'uwypuklenia' dziwnych czasów wykonywania sortowań
$this->mySort($this->a);

Ta petla jest totalnie bezsensu, gdyz po pierwszym obrocie masz juz posortowaną tablicę i w kazdym kolejnym obrocie sortujesz posortowane juz dane.
Shlizer
Połowicznie masz rację.. tj. jest o tyle bez sensu, że tablica jest posortowana, ale wciąż trzeba przez nią przelecieć, żeby to sprawdzić =p
W przykładzie online (http://ideone.com/Z4tTUV) już poprawiłem tworząc tymczasową tablicę z testowej, tylko do obliczeń..

EDIT: przy tworzeniu tablic zobaczyłem także, że niepotrzebnie podaję indeks dla nowych elementów, szczególnie przy losowej tablicy ($arr[$i] = $i). Zmieniłem na pusha, żeby indeksy same się inkrementowały.
Pyton_000
znajdź różnice
  1. public function __constructor($array) {

  1. public function __construct($array) {
Shlizer
Jak już napiszę książkę 'O tym jak literówka zmarnowała mi kilka dni życia' to przyślę Ci egzemplarz z podpisem -.-

Faktycznie to tutaj wkradł się błąd.. dzięki za wytknięcie go.. masakra.. chyba słusznie wrzuciłem to do przedszkola 0o
Pyton_000
Chętnie przeczytam książkę smile.gif Po śmierci będziesz sławny.
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.