ugrás a tartalomhoz

konstans vs. assz.tömb

Anonymous · 2006. Már. 1. (Sze), 10.36
Sziasztok, lenne egy kérdésem, adott egy config.php tele mindenféle (lassan már 200 darab) beállítással. Melyik és miért jobb? Konstansokat használjak vagy egy nagy asszociatív tömböt, esetleg több kisebb asszociatív tömböt? Milyen előnyei, hátrányai vannak ezeknek? (azon kívül, hogy ízlés dolga?:-)
 
1

Asszociatív tömb...

-zsolti- · 2006. Már. 1. (Sze), 11.22
...mert gyorsabb.
2

teszt?

Hodicska Gergely · 2006. Már. 4. (Szo), 16.45
Szia!


Ezt mire alapozod? Egyrészt túl nagy különbség szerintem nem lehet köztük, de ha van is, kérdés hogy egyáltalán mennyire számottevő-e. Ezenkívül (ez csak tipp, nem néztem utána) de egy tömbelem elérése drágább lehet, mint egy konstansé.

Itt szerintem egyéb szempontok alapján lenne érdemesebb dönteni. Pl. a konstansok esetén nem láthatósággal foglalkozni, viszont nem tudod módosítani a tartalmát stb..


Felhő
3

Teszt szerint...

-zsolti- · 2006. Már. 4. (Szo), 20.21
...a konstans elérése a drágább, de ahogy te is írtad, nem számottevően.

200 darab konstans közül kiválasztani a x-ediket 0.0004 másodperc, még egy ugyanilyen asszociatív tömbből kiválasztani ugyanazt 0.0002 másodperc.
(Ui. mindez PHP4-ben. PHP4 előtt állítólag* még a tömbelérés sokkal lassabb volt.)
* Nem próbáltam, csak olvastam.
4

Hogyan tesztelted?

Hodicska Gergely · 2006. Már. 5. (V), 01.32
Kíváncsi lennék arra a tesztre. Én eleve arra gondoltam, hogy a konstansnak és a tömbnek megfelelő adatstruktúrát is ugyanannyi idő alatt éri el a PHP, de a tömb esetén még a kívánt elemt is ki kell szedni belőle.

Az én tesztem ezt igazolta is. Jópárszor futtatva mindig minimum 2,5-szer gyorsabb volt a konstans. Az olvasott teszteket nem érdemes készpénznek venni, mert verziórol verzióra történhetnek változások, meg lehetnek eleve hibásak is. Érdemesebb inkább kipróbálni őket. Bár jelen esetben nem sok különbség van.


Felhő

<?php
// PHP 4.3.10, WinXP SP2

	for($i = 1; $i <= 20; $i++) {
		define('CONST'.$i, $i);
		$array[$i] = $i;
	}


	$clock = new ClockUtil();


	$clock->Start('const');
	for($j = 1; $j <= 10000; $j++) {
		$foo = CONST1;
		$foo = CONST2;
		$foo = CONST3;
		$foo = CONST4;
		$foo = CONST5;
		$foo = CONST6;
		$foo = CONST7;
		$foo = CONST8;
		$foo = CONST9;
		$foo = CONST10;
		$foo = CONST11;
		$foo = CONST12;
		$foo = CONST13;
		$foo = CONST14;
		$foo = CONST15;
		$foo = CONST16;
		$foo = CONST17;
		$foo = CONST18;
		$foo = CONST19;
		$foo = CONST20;
	}
	echo 'Const: '.$clock->Stop('const').'<br/>';

	$clock->Start('array');
	for($j = 1; $j <= 10000; $j++) {
		for($i = 1; $i <= 20; $i++) {
			$foo = $array[$i];
		}
	}
	echo 'Array: '.$clock->Stop('array').'<br/>';
?>
<?php
	class ClockUtil {
		var $_clocks = array();


		function Start($handler, $reset = false)
		{
			if (!isset($this->_clocks[$handler]) || $reset) {
				$this->_clocks[$handler] = $this->_GetTime();
				return true;
			} else {
				trigger_error('The clock named '.$handler.' was already started!', E_USER_WARNING);
				return false;
			}
		}


		function Stop($handler)
		{
			if (isset($this->_clocks[$handler])) {
				$elapsedTime = $this->_GetTime() - $this->_clocks[$handler];
				unset($this->_clocks[$handler]);

				return $elapsedTime;
			} else {
				trigger_error('The clock named '.$handler.' was not started!', E_USER_WARNING);
				return false;
			}
		}


		function Read($handler)
		{
			if (isset($this->_clocks[$handler])) {
				return $this->_GetTime() - $this->_clocks[$handler];
			} else {
				trigger_error('The clock named '.$handler.' was not started!', E_USER_WARNING);
				return false;
			}
		}


		function _GetTime()
		{
			list($usec, $sec) = explode(' ', microtime());
			return (float)$usec + (float)$sec;
		}
	}
?>
6

Két külön fájlban...

-zsolti- · 2006. Már. 5. (V), 14.34
...végeztem, nem egymás után tettem, és az elemeket sem ciklusban hoztam létre, hanem statikusan volt minden a forrásban:

Define.php:
<?php

/** Oldalgenerálás mérését végző osztály */
    require_once('PageGeneration.class.php');
    $pageGen = new PageGeneration();
    
define('a1', 'something');
define('a2', 'something');
...
define('a200', 'something');

$b = a1;

echo $pageGen->getGeneration(8, true);    
    
?>
Array.php:
<?php

/** Oldalgenerálás mérését végző osztály */
    require_once('PageGeneration.class.php');
    $pageGen = new PageGeneration();
    
$x = array(
  'a1' => 'something',
  'a2' => 'something',
  ...
  'a200' => 'something'
);

$b = $x['a1'];

echo $pageGen->getGeneration(8, true);    
    
?>
(A PageGeneration osztályom gyakorlatilag ugyanaz, mint nálad a clockUtil.)
8

Kavar a tesztben

Hodicska Gergely · 2006. Már. 5. (V), 15.13
Ebben a tesztben össze van keverve a létrehozás és az elérés. Mint kiderült a létrehozás lassabb csak konstansok esetében, viszont az elérésük jóval gyorsabb.


Felhő
9

Nincs összekeverve...

-zsolti- · 2006. Már. 5. (V), 15.37
...direkt úgy mértem, ahogy a "valós életben" is szembesülhetünk a vele. (Legalábbis nálam nem maguktól "tűnnek fel" a konstansok, így a létrejöttük is beleszámítódik a futásidőbe.)

(A 3. hsz-ben helytelenül fogalmaztam, elérés => futásidő. Tehát a teljes megvalósítsára értettem az állítást, nem arra a részfeladatra, amikor már csak az elérés történik.)
10

arányok

Hodicska Gergely · 2006. Már. 5. (V), 16.17
..direkt úgy mértem, ahogy a "valós életben" is szembesülhetünk a vele. (Legalábbis nálam nem maguktól "tűnnek fel" a konstansok, így a létrejöttük is beleszámítódik a futásidőbe.)

Csak a valós életben elég erősen függ az alkalmazástól, hogy mi a létrehozás és az elérés aránya. Az én keretrendszeremben például egy rakat alap konstanst nagyon sokszor használok (különböző típusú objektumok példányosítása többnyire), egy részüket ritkábban, de általában többször érem el őket, mint ahányszor definiálom őket.

(A 3. hsz-ben helytelenül fogalmaztam, elérés => futásidő. Tehát a teljes megvalósítsára értettem az állítást, nem arra a részfeladatra, amikor már csak az elérés történik.)

Sorry, de ezt nem tudhattam.


Felhő
5

Másik teszt

Balogh Tibor · 2006. Már. 5. (V), 13.34
Hát a Schlossnagle könyvben is félreérthetően, majdhogynem elmarasztalóan írnak a define utasításról, és mások is írták már a php listán, hogy az APD-vel mérték a programjuk futását, és hogy kimagaslóan sok időt vett igénybe a define végrehajtása.

Nos, végül is utánna jártam magam is a dolognak. Készítettem egy szkriptet amiben először 1000 majd 10000 konstans és változó létrehozásának idejét próbáltam összehasonlítani. A szkript valahogy így festett.
<?php
	apd_set_pprof_trace();
	start_test();

	$foo = 1;
	.
	...

	start_define();

	define ('foo', 1);
	.
	..
?>
A szkriptet egy másik szkript állította elő, rendre megegyeztek a változók és a konstansok nevei és értékei is, véletlenszerűen állította elő a név-érték párosokat. Akit érdekel, gondolom nem okoz neki gondot létrehozni egy hasonló szkriptet, már nem tudom hova tettem a mérést legyártó szkriptet.

A beszúrt függvények semmit nem csináltak, csak kiírták, hogy start..., azért kellettek, hogy az APD-vel lehessen mérni a különbséget. A méréskor az jött ki, hogy semmi különbbség nincs a konstans és a változók használata között, sőt kicsit gyorsabban lehet létrehozni konstanst, mint változót.

Megjegyzendő, hogy a konstansok létrehozásának idejét jól le lehetett olvasni az APD kimenetén, de a változók létrehozásának ideje nem a main sornál jelent meg, hanem az apd_set_pprof_trace függvénynél. Amennyivel nőtt az apd_set_pprof_trace függvény végrehajtási ideje, amennyivel a define-ek ideje, ez valószínűleg bug.

Akkor felmerül a kérdés, hogy mégis miért tesz ki jelentős értéket mérésnél a konstansok létrehozása. A válasz valószínűleg az, hogy a memóriafoglalás költséges művelet. Változók és konstansok létrehozásakor memóriaterületeket kell lefoglalni futásidőben. De most nehogy arra következtessen már valaki, hogy mostantól nem fog változókat, konstansokat használni.

A define-ek végrehajtási ideje a már memóriában lévő dolgokon elvégzett műveletekhez képest lassúak, vagy akkor ha több tucat - 70, 80 db - végrehajtási idejét hasonlítjuk valami más egyszerűbb művelethez.

Az elérési idejüket nem mértem, de valószínűleg egy konstans elérése - ha minimálisan is de - gyorsabb, mint egy tömbelemé. Ellenben a tömbelemeket hatékonyabban lehet használni különböző programszerkezetekben, pl. ciklusban; kiíratásnál, értékadásoknál.
7

létrehozás tényleg lassabb

Hodicska Gergely · 2006. Már. 5. (V), 15.07
Létrehozás tényleg lassabb konstansok esetében, de Zsolt az elérésről beszélt. Az alábbi példán ez látható is. Persze a 20 nem egy nagy szám, de akárhányszor futtattam, mindig lassabb volt a konstans.
De ez mind nem túl számottevő, szóval nem ez alapján érdemes választani.


Felhő
<?php
	$clock = new ClockUtil();


	$clock->Start('const');
	for($i = 1; $i <= 20; $i++) {
		define('CONST'.$i, $i);
	}
	$foo = CONST1;
	$foo = CONST2;
	$foo = CONST3;
	$foo = CONST4;
	$foo = CONST5;
	$foo = CONST6;
	$foo = CONST7;
	$foo = CONST8;
	$foo = CONST9;
	$foo = CONST10;
	$foo = CONST11;
	$foo = CONST12;
	$foo = CONST13;
	$foo = CONST14;
	$foo = CONST15;
	$foo = CONST16;
	$foo = CONST17;
	$foo = CONST18;
	$foo = CONST19;
	$foo = CONST20;
	echo 'Const: '.$clock->Stop('const').'<br/>';


	$clock->Start('array');
	for($i = 1; $i <= 20; $i++) {
		$array[$i] = $i;
	}
	for($i = 1; $i <= 20; $i++) {
		$foo = $i;
	}
	echo 'Array: '.$clock->Stop('array').'<br/>';
?>
<?php
	class ClockUtil {
		var $_clocks = array();


		function Start($handler, $reset = false)
		{
			if (!isset($this->_clocks[$handler]) || $reset) {
				$this->_clocks[$handler] = $this->_GetTime();
				return true;
			} else {
				trigger_error('The clock named '.$handler.' was already started!', E_USER_WARNING);
				return false;
			}
		}


		function Stop($handler)
		{
			if (isset($this->_clocks[$handler])) {
				$elapsedTime = $this->_GetTime() - $this->_clocks[$handler];
				unset($this->_clocks[$handler]);

				return $elapsedTime;
			} else {
				trigger_error('The clock named '.$handler.' was not started!', E_USER_WARNING);
				return false;
			}
		}


		function Read($handler)
		{
			if (isset($this->_clocks[$handler])) {
				return $this->_GetTime() - $this->_clocks[$handler];
			} else {
				trigger_error('The clock named '.$handler.' was not started!', E_USER_WARNING);
				return false;
			}
		}


		function _GetTime()
		{
			list($usec, $sec) = explode(' ', microtime());
			return (float)$usec + (float)$sec;
		}
	}
?>
11

Tesztelőknek

Bártházi András · 2006. Már. 5. (V), 16.21
Fijúk, odaírhatnátok azt is, hogy melyik PHP verzióval teszteltek, esetleg hogy milyen oprendszeren. A PHP 4/PHP 5 között is lehetnek különbségek, illetve egy Windows és egy Linux memória menedzsmentjében is.

Azon az pár század másodpercen, ami a kettő megoldás közti különbség, tényleg érdemes szerintetek ennyit gondolkodni? :)

-boogie-
13

persze

Hodicska Gergely · 2006. Már. 5. (V), 17.46
Fijúk, odaírhatnátok azt is, hogy melyik PHP verzióval teszteltek, esetleg hogy milyen oprendszeren. A PHP 4/PHP 5 között is lehetnek különbségek, illetve egy Windows és egy Linux memória menedzsmentjében is.

Ezt már beláttuk korábban, volt róla szó, de jogos. Enyémet javítottam.

Azon az pár század másodpercen, ami a kettő megoldás közti különbség, tényleg érdemes szerintetek ennyit gondolkodni? :)

Erre is írtuk, hogy nem, de van akit érdekel, hogy mi van a dolgok mélyén, van akit nem.


Felhő
12

Másik teszt

Balogh Tibor · 2006. Már. 5. (V), 17.28
Válasz a Felhő 7. bejegyzésére, azért külön, hogy kiférjenek az ablakok. Mint írtam, nem így mértem, mivel nem így szokták definiálni a konstansokat. Valóban a mérési módszered szerint lassabb a define végrehajtása. De a fönt leírt mérési módszerem szerint egyáltalán nem lassabb PHP-ben a konstansok létrehozása.

Az általad ajánlott módszer szerint:
<?php
	apd_set_pprof_trace();

	function make_define($max){
		for ($i = 0; $i < $max; ++$i){
			define ('CONST'.$i, $i);
		}
	}
	function make_array($max){
		for ($i = 0; $i < $max; ++$i){
			$foo['CONST'.$i] = $i;
		}
	}

	$max = 100;
	make_define($max);
	make_array($max);
?>
A mérés eredménye:

$>php pprofp.php -Ri pprof.03736.0
X-Powered-By: PHP/4.4.1
Content-type: text/html

Trace for define_test.php
Total Elapsed Time =  0.01s
Total System Time  =  0.00s
Total User Time    =  0.01s

            Real         User        System              secs/   cumm
 Time%  (excl/cumm)  (excl/cumm)  (excl/cumm)   Calls    call   s/call   Memory Usage  Name
-------------------------------------------------------------------------------------------
 100.0   0.00  0.01   0.00  0.01   0.00  0.00        1  0.0001  0.0062              0  main
  56.5   0.00  0.00   0.01  0.01   0.00  0.00        1  0.0035  0.0035              0  make_define
  32.1   0.00  0.00   0.00  0.00   0.00  0.00        1  0.0020  0.0020              0  apd_set_pprof_trace
  10.5   0.00  0.00   0.00  0.00   0.00  0.00        1  0.0007  0.0007              0  make_array
De az előző hozzászólásomnál írt módszerrel mérve a következő lett az eredmény. Ennél a hívási fánál megjelenített időket kell nézni, mert valamiért a változók létrehozásának ideje az apd_set_pprof_trace függvény hívásánál jelentkezik. Egyébként a változók létrehozása az end_define és az end_test között voltak. A mérő szkript több mint 10000 konstanst és ugyanennyi változót tartalmazott. A fenti módszerrel mérve, közel ugyanannyi a konstansok létrehozásának ideje. A változók létrehozása: 0.38 mp, a konstansoké: 32 mp, de a 0.38 eredményben egyébb dolgok inicializálása is beletartozhat.

A mérő szkript:
<?php
	apd_set_pprof_trace();
	start_test();

		define ('FEQFFN', 137599);
		//További define utasítások
		...

	end_define();

		$FEQFFN = 137599;
		//További változók definiálása
		...

	end_test();
?>
A mérés eredménye:

$>php pprofp.php -RTci pprof.01016.0
X-Powered-By: PHP/4.4.1
Content-type: text/html

 0.00s main
 0.00s   apd_set_pprof_trace
 0.38s   start_test
 0.70s   end_define
 0.71s   end_test

Trace for define_compare.php
Total Elapsed Time =  0.74s
Total System Time  =  0.03s
Total User Time    =  0.60s

            Real         User        System              secs/   cumm
 Time%  (excl/cumm)  (excl/cumm)  (excl/cumm)   Calls    call   s/call   Memory Usage  Name
-------------------------------------------------------------------------------------------
 100.0   0.31  0.74   0.26  0.60   0.02  0.03        1  0.3149  0.7449              0  main
  50.8   0.38  0.38   0.31  0.31   0.01  0.01        1  0.3784  0.3784              0  apd_set_pprof_trace
   5.1   0.04  0.04   0.03  0.03   0.00  0.00        1  0.0378  0.0378              0  end_test
   1.5   0.01  0.01   0.00  0.00   0.00  0.00        1  0.0109  0.0109              0  start_test
   0.4   0.00  0.00   0.00  0.00   0.00  0.00        1  0.0030  0.0030              0  end_define