Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Lista obiektów
Forum PHP.pl > Forum > PHP > Object-oriented programming
DeyV
Zastanawiam się ostatnio nad takim zagadnieniem.

Mam w systemie dużą (kilkaset elementów) listę obiektów tego samego typu, z których każdy ma swoją unikalną nazwę. Każdy z nich spełnia jednak różne zadania, w związku z czym muszę je mieć dostępne w kilku miejscach równocześnie.
Oznacza to, że mam je zarejestrowane w tablicy podstawowej, chciałbym jednak mieć również wydzielone specjalne tablice pomocnicze, przechowujące informacje o obiektach konkretnie mnie interesujących.

Tu jednak pojawia się pytanie.
Czy taka tablica powinna zawierać liste identyfikatorów obiektów ( typu 'NazwaObiektu1') czy też lepiej by było, by zawierała od razu referencje do tych obiekcików.

I nie chodzi tu o funkcjonalność, a o wydajność i zużycie pamięci.

Czy ktoś z Was robił kiedyś testy tego typu?

Ja niestety - nie mogę tego zrobić, ponieważ nie mam dostępu do maszyny z biblioteką zajmującą się pomiarem zużycia pamięci przez php.


przykład:
  1. <?php
  2. $aLista = array( 
  3.  'Obiekt1' => new Obiekt(),
  4.  'Obiekt2' => new Obiekt(),
  5.  'Obiekt3' => new Obiekt(),
  6. );
  7. ?>


rozwiązanie pierwsze (identyfikatory):
  1. <?php
  2. $aListaPomocnicza = array( 'Obiekt1' , 'Obiekt3' );
  3. ?>


rozwiązanie drugie (referencje):
  1. <?php
  2. $aListaPomocnicza = array( 
  3.  $aLista[ 'Obiekt1' ],
  4.  $aLista[ 'Obiekt3' ],
  5. );
  6. ?>
bigZbig
Zadaj sobie pytanie w jaki sposob bedziesz sie odwolywal do konkretnego elementu z listy pomocniczej - $aListaPomocnicza['79'] - czy raczej zdecydujesz sie na klucze w postaci tekstowej pozwalajace latwiej zidentyfikowac konkretny obiekt.

Jesli bedziesz sie odwolywal przy pomocy indeksow liczbowych to Twoj problem pozostaje nierozstrzygniety gdyz nie potrafie Ci powiedziec co zajmuje wiecej miejsca w pamieci - nazwa obiektu czy wskaznik do niego.

Jesli chcesz miec mozliwosc wskazywania konkretnego obiektu po jego nazwie to z logicznego punktu widzenia rozwiazanie pierwsze wydaje się być najwlasciwsze.
DeyV
Niestety - tak jak napisałem - nie chodzi tu o funkcjonalność, gdyż lista pomocnicza ma być tylko i wyłącznie iterowana - nie są więc w niej potrzebne klucze.

Dlatego właśnie pojawiło się pytanie - czy lepiej jest przechowywać tablicę stringów (identyfikatorów) czy referencji.
em1X
Ja zrobiłbym to na referencji.. kto wie.. z nazwami coś się może wysypać... a referencją zwalasz wszystko na system. A skoro to jeszcze ma byc iterowane cool.gif ...
dr_bonzo
Wyniki dla 80000 obiektow:
Kod
                           list creation : 104.79511 MB
                referencing by reference : 03.55194 MB
                referencing by reference : 00.14405 s

                           list creation : 104.79511 MB
          referencing by key name STRING : 05.38295 MB
          referencing by key name STRING : 00.28383 s

                           list creation : 104.79511 MB
         referencing by key name INTEGER : 04.77258 MB
         referencing by key name INTEGER : 00.19460 s


Czyli
* ilosc zajmowanego miejsca (im mniej tym lepiej):
referencje < integer < string
Poza tym same obiekty zajmuja ok. 25x wiecej niz tablia z referencjami/indeksami do tych obiektow

* Szybkosc dostepu do obiektow (im mniej tym lepiej):
referencje < integer < string


Wniosek: referencje sa najszybsze i zajmuja najmniej miejsca, choc w porownaniu z tablica obiektow kazda metoda zajmuje duzo mniej miejsca.


PS. Nie nalezy uruchamiac trzech testow za jednym razem, php osiagaja granice dostepnej pamieci, usuwa niepotrzebne obiekty/dane przez co po utworzeniu tablicy mozemy otrzymac wieksza ilosc wolnej pamieci niz przed (stare obiekty usuniete w czasie tworzenia nych --> zuzycie pamieci ujemne smile.gif)


Test:
  1. <pre>
  2. memory_limit = 128M
  3. php 5.1.5
  4. <?php
  5.  
  6. define( 'OBJECTS_COUNT', 80000 );
  7. //define( 'ARRAY_KEY_PREFIX', 'very_long_array_key_prefix' );
  8. define( 'ARRAY_KEY_PREFIX', '' );
  9. define( 'Xth', 1 );
  10.  
  11.  
  12. $test_type = @$_GET[ 'test' ];
  13. $test_type = ($test_type) ? $test_type : 'lol';
  14.  
  15. print( '<a href="?test=reference">reference</a><br />' );
  16. print( '<a href="?test=string">string</a><br />' );
  17. print( '<a href="?test=integer">integer</a><br />' );
  18.  
  19.  
  20. class Object
  21. {
  22. private $name = "lol.";
  23. private $count = 100;
  24. private $largeString = '';
  25.  
  26. public function __construct()
  27. {
  28. $this->largeString = str_repeat( '1234567890', 100 );
  29. }
  30. }
  31.  
  32. function createInitialList( $count )
  33. {
  34. $list = array();
  35. for ( $i = 0; $i < $count; $i++ )
  36. {
  37. $list[ $i ] = new Object();
  38. }
  39.  
  40. return $list;
  41. }
  42.  
  43. function printTimeDelta( $end, $start, $msg )
  44. {
  45. printf( "%40s : %08.5f s<br />", $msg, ( $end - $start ) );
  46. }
  47.  
  48. function printMemoryUsage( $end, $start, $msg )
  49. {
  50. printf( "%40s : %08.5f MB<br />", $msg, ( ( $end - $start ) / 1048576 ) );
  51. }
  52.  
  53. function pickEveryXthItemReferences( $array, $X )
  54. {
  55. $count = count( $array );
  56. $newArray = array();
  57.  
  58. for ( $i = 0; $i < $count ; $i += $X )
  59. {
  60. $newArray []= $array[ $i ]; // zapisz referencje do obiektu
  61. }
  62.  
  63. return $newArray;
  64. }
  65.  
  66. function pickEveryXthItemKeyNameInteger( $array, $X )
  67. {
  68. $count = count( $array );
  69. $newArray = array();
  70.  
  71. for ( $i = 0; $i < $count ; $i += $X )
  72. {
  73. $newArray []= $i; // zapisz indeks tablicy
  74. }
  75.  
  76. return $newArray;
  77. }
  78.  
  79. function pickEveryXthItemKeyNameString( $array, $X )
  80. {
  81. $count = count( $array );
  82. $newArray = array();
  83.  
  84. for ( $i = 0; $i < $count ; $i += $X )
  85. {
  86. $newArray [ ARRAY_KEY_PREFIX . $i ]= ARRAY_KEY_PREFIX . $i; // zapisz indeks (jako stringa) tablicy
  87. }
  88.  
  89. return $newArray;
  90. }
  91.  
  92. $memStart = 1;
  93. $memEnd = 1;
  94.  
  95. $timeStart = 0.1;
  96. $timeEnd = 0.1;
  97.  
  98. // utworzaenie listy obiektow, indeksowanych 0,1,...
  99. $memStart = memory_get_usage(); 
  100. $objectList = createInitialList( OBJECTS_COUNT );
  101. $memEnd = memory_get_usage(); 
  102. printMemoryUsage( $memEnd, $memStart, "list creation" );
  103.  
  104.  
  105. switch ( $test_type )
  106. {
  107. case 'reference':
  108. {
  109. // tablica zawiera referencje do obiektow
  110. $memStart = memory_get_usage(); 
  111. // wybranie polowy obiektow do nowej tablicy
  112. $list_references = pickEveryXthItemReferences( $objectList, Xth);
  113. $memEnd = memory_get_usage(); 
  114. printMemoryUsage( $memEnd, $memStart, "referencing by reference" );
  115.  
  116. $timeStart = microtime( true );
  117. foreach ( $list_references as $item )
  118. {
  119. $x = $item;
  120. $x = NULL;
  121. }
  122. $timeEnd = microtime( true );
  123.  
  124. printTimeDelta( $timeEnd, $timeStart, "referencing by reference" );
  125. break;
  126. }
  127. case 'string':
  128. {
  129. // tablica zawiera indeksy tablicy $objectList
  130. // indeksy sa STRINGAMI
  131. $memStart = memory_get_usage(); 
  132. // wybranie polowy obiektow do nowej tablicy
  133. $list_keysString = pickEveryXthItemKeyNameString( $objectList, Xth);
  134. $memEnd = memory_get_usage(); 
  135. printMemoryUsage( $memEnd, $memStart, "referencing by key name STRING" );
  136.  
  137. $timeStart = microtime( true );
  138. foreach ( $list_keysString as $key )
  139. {
  140. $x = $objectList[ (int)$key ];
  141. $x = NULL;
  142. }
  143. $timeEnd = microtime( true );
  144.  
  145. printTimeDelta( $timeEnd, $timeStart, "referencing by key name STRING" );
  146. break;
  147. }
  148. case 'integer':
  149. {
  150. // tablica zawiera indeksy tablicy $objectList
  151. // indeksy sa liczbami!!
  152. $memStart = memory_get_usage(); 
  153. // wybranie polowy obiektow do nowej tablicy
  154. $list_keysInteger = pickEveryXthItemKeyNameInteger( $objectList,Xth);
  155. $memEnd = memory_get_usage(); 
  156. printMemoryUsage( $memEnd, $memStart, "referencing by key name INTEGER" );
  157.  
  158. $timeStart = microtime( true );
  159. foreach ( $list_keysInteger as $key )
  160. {
  161. $x = $objectList[ $key ];
  162. $x = NULL;
  163. }
  164. $timeEnd = microtime( true );
  165.  
  166. printTimeDelta( $timeEnd, $timeStart, "referencing by key name INTEGER" );
  167.  
  168. break;
  169. }
  170. default :
  171. {
  172. print( '.....' );
  173. }
  174. }
  175.  
  176. reset( $objectList ); // proba zapobiegniecia wyrzuceniu z pamieci tablicy $objectList
  177. /*
  178.   nie nalezy uruchamiac 3ech trestow na raz, gdyz php uruchamia garbagecollectora,
     gdy konczy mu sie pamiec, co znieksztalca wyniki
  179.   */
  180. ?></pre>


---
sorry za taki burdel w kodzie, ale spojrzcie na zegar smile.gif
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-2024 Invision Power Services, Inc.