DarkSide Posted October 24, 2006 Report Share Posted October 24, 2006 Sveiki! Vai ir kādas idejas kādēļ lieli foreach cikli norij nenormāli daudz servera (Apache procesa) RAM atmiņas. Lietoju, Apache 1.3.x, PHP 4.x, Win2K. Skripts ir piemēram šāds: foreach($arrData['DEPARTMENTS'] as $did=>$dvalue) { foreach($dvalue['CONTRACTS'] as $cid=>$cvalue) { foreach($cvalue['ORDERS'] as $oid=>$ovalue) { echo "$did, $cid, $oid"; } } } Ideja tāda, ka man ir viens liels strukturēts masīvs $arrData, ko man ir jāparsē cauri un kautkas ar tiem datiem jāizdara (piemēram, jāizdrukā uz ekrāna). Ejot cauri šiem foreachiem Apache aprij ~200Mb RAM!! :-))) Ko tā? Reāli taču RAMu apēst nevajadzēja praktiski nemaz, jo katrā ciklu solī es papildus jau esošajam $arrData masīvam izveidoju principā tikai vienu mainīgo... lai gan piemēram $dvalue sanāk riktīgi liels... hmm... ok - padomāšu pats vēl par šo tēmu, bet anyway varbūt ir kādi noderīgi komentāri par foreach optimizāciju (uz PHP4). Link to comment Share on other sites More sharing options...
bubu Posted October 24, 2006 Report Share Posted October 24, 2006 Cik tev daudz elementu aptuveni ir katrā masīvā dimensijā? Link to comment Share on other sites More sharing options...
v3rb0 Posted October 24, 2006 Report Share Posted October 24, 2006 kaut kur dzirdēju, ka foreach taisa masīva kopiju un tāpēc vietās kur ar for vai while var iztikt labāk izmantot tos. bet 200MB vienalga tur nesanāks, kauč 3kopijas taisa. pieņemu ka struktūra nav uz 100 megabaitiem. Link to comment Share on other sites More sharing options...
GedroX Posted October 24, 2006 Report Share Posted October 24, 2006 Pēc ātrdarbības foreach bija ātrākais paņēmiens, lai izskrietu caur masīvu. Man gan liekās, ka vajadzētu filtrēt datus jau db līmenī. 200Mb ir toč par traku. Mēģini šādi: $a1 = array_keys($arrData['DEPARTMENTS']); foreach($a1 as $did) { $a2 = array_keys($arrData['DEPARTMENTS'][$did]['CONTRACTS']); foreach($a2 as $cid) { $a3 = array_keys($arrData['DEPARTMENTS'][$did]['CONTRACTS'][$cid]['ORDERS']); foreach($a3 as $oid) { echo $did . ', ' . $cid . ', ' . $oid; } } } unset($a1, $a2, $a3); Ja tie tev ir objekti, tad var izmantot sintaksi foreach ($obj as $k => &$v). Link to comment Share on other sites More sharing options...
DarkSide Posted October 24, 2006 Author Report Share Posted October 24, 2006 Daži parametri: strlen(serialize($arrData)) = ~10'000'000 tas ir apmēram 10Mb. Grozies kā gribi, pat ja foreach patiešām būtu pilnīgi garām un taisītu 10 kopijas no pilnīgi visa $arrData tad tik un tā nesanāktu ~200Mb. Saskaitīju kopā ar šo pašu funkciju strlen(serialize($foo)) pilnīgi visus mainīgos kas izmantoti šais foreachos un tik un tā sanāca kopā apmēram 25'000'000 jeb 25Mb... P.S. Tur nav objektu - tas ir pliks masīvs tikai ar samērā dziļu struktūru. un foreachi īstenībā ir 5 gab. nevis 3 kā parādīju piemērā. Cik tev daudz elementu aptuveni ir katrā masīvā dimensijā? Departments kādi 10-20, Contracts kādi 1000-5000, Orders arī +/- tikpat cik Contracts Link to comment Share on other sites More sharing options...
bubu Posted October 24, 2006 Report Share Posted October 24, 2006 Arī ja tie nav objekti, tad der pamēģināt references. Link to comment Share on other sites More sharing options...
DarkSide Posted October 24, 2006 Author Report Share Posted October 24, 2006 kaut kur dzirdēju, ka foreach taisa masīva kopiju un tāpēc vietās kur ar for vai while var iztikt labāk izmantot tos.bet 200MB vienalga tur nesanāks, kauč 3kopijas taisa. pieņemu ka struktūra nav uz 100 megabaitiem. Pat ja būtu visprastākā kopija - nu labi - tad 2x paņemtu RAM, bet struktūra ir uz apmēram 10Mb nevis 100Mb. Arī ja tie nav objekti, tad der pamēģināt references.Laikam man rokas līkas, bet foreach($array as $key => &$value) man nešansē. Piesienas pie &. Kurā brīdī Tu domāji tās references izmantot? Link to comment Share on other sites More sharing options...
GedroX Posted October 24, 2006 Report Share Posted October 24, 2006 Izmēģināji manis ieteikto variantu ar array_keys? Cik zinu, ar masīviem nestrādā paņēmiens foreach ($array as $key => &$value). Vai varbūt jaunākajās versijās strādā? Link to comment Share on other sites More sharing options...
bubu Posted October 24, 2006 Report Share Posted October 24, 2006 Hm.. nestrādā? Varbūt arī nē, jāpamēģina ;) Vai ar each() fju arī mēģināji apstaigāt masīvus? Link to comment Share on other sites More sharing options...
DarkSide Posted October 24, 2006 Author Report Share Posted October 24, 2006 Izmēģināji manis ieteikto variantu ar array_keys? Cik zinu, ar masīviem nestrādā paņēmiens foreach ($array as $key => &$value). Vai varbūt jaunākajās versijās strādā? Šitais variants nekādu lielo ieguvumu nedod (varbūt pāris Mb) - skat.zemāk ko atradu... Hm.. nestrādā? Varbūt arī nē, jāpamēģina ;) Vai ar each() fju arī mēģināji apstaigāt masīvus? each() līdzīgi kā ar array_keys - nekāds lielais ieguvums (varbūt pāris nepamanāmi Mb). Skat.zemāk... Lūk ko atradu - tikai to nu es vēl vairāk nesaprotu :-) Lūk nedaudz papildināts mans kods(skatīt to $first_row): $row_id = 0; foreach($arrData['DEPARTMENTS'] as $did=>$dvalue) { foreach($dvalue['CONTRACTS'] as $cid=>$cvalue) { $first_row = true; foreach($cvalue['ORDERS'] as $oid=>$ovalue) { if($first_row) $first_row=false; else $row_id++; echo "$row_id, $did, $cid, $oid"; } } } Tas gan arī nav pilnīgi viss kods, bet pati sāls tur ir. Tad nu lūk, līdzko es izkomentēju ārā to rindiņu if($first_row) $first_row=false; else $row_id++;, tā Apache vairs apēd nevis 200Mb RAM bet gan tikai 100Mb. Vot tas jau man pavisam nepielec. Sanāk, ka problēma bija ne tik daudz tajos foreachos, bet gan ar kautkādu IFu??? Sviests. Kādas idejas? Link to comment Share on other sites More sharing options...
GedroX Posted October 24, 2006 Report Share Posted October 24, 2006 Lielos ciklos vajaga censties maksimāli vienkāršot kodu. Labāk sadali pēdējo ciklu divās daļās. Link to comment Share on other sites More sharing options...
DarkSide Posted October 24, 2006 Author Report Share Posted October 24, 2006 (edited) Lielos ciklos vajaga censties maksimāli vienkāršot kodu. Labāk sadali pēdējo ciklu divās daļās.Hmm.... sadalīt to ciklu es nevaru, jo tas echo tur ir tikai kā piemērs, īstenībā ir bišķi sarežģītāk... Visu kodu te nelikšu - sanāks pārāk gari...BET viena ideja man radās, anyway šitie foreachi apēd kādus 100Mb, bet otri 100Mb rodas pēc šiem foreachiem, kad izmantojot to $row_id (tāpēc itkā bremzēja ifs, jo row_id palika stipri lielāks nekā bez tā ifa) es pēc tam ģenerēju izdrukas tabulu. Savukārt, šī izdrukas tabula ir objekts, kas acīmredzot uz PHP4 kautkā gļukaini norij RAMu. Statistika - izdrukas tabulas objekts strlen(serialize(objekc)) = ~9Mb, bet tad es to tabulu "normalizēju", respektīvi aizpildu tukšās celles, sakārtoju colspanus utml. un pēc tās "normalizēšanas" izdrukas tabulas objekts jau aizņem strlen(serialize(objekc)) = ~17Mb... Ja pieņemam, ka PHP4 kautko vēl ar objektiem nogļuči, tad varbūt var arī sanākt tie apmēram 100Mb... :( Vienvārdsakot, paēdīšu "pusdienas" un izpētīšu līdz galam. Tad jau došu ziņu ko jaunu būšu noskaidrojis :) Paldies Jums! Edited October 24, 2006 by DarkSide Link to comment Share on other sites More sharing options...
Delfins Posted October 24, 2006 Report Share Posted October 24, 2006 (edited) Nū... ka jau teica.. jāiet cauri ar array_keys... Un nevis vienam līmenim, bet visiem trīs.. for ( i=0; i<keysCnt; i++ ) { keysJ = array_keys( $arr[keys[i]] ); for ( j=0; j<keysJCnt; j++ ) { ... } } PS: kaut gan laiku patērē vairāk... Edited October 24, 2006 by Delfins Link to comment Share on other sites More sharing options...
Robis Posted October 24, 2006 Report Share Posted October 24, 2006 Koroč, viss tev tur galīgi ***** vecīt, domā ar galvu - masīvu tīklotā cilpošana vispār paņem daudz resursus! Meklē, mēģini, dalies. Vispirms - protams, sameklē google.lv pēc "array loops php" - atrodi kādus variantus, izmēģini iespējamos variantus. Tālāk - nu ja nesanāk, ta nav lemts! :D Link to comment Share on other sites More sharing options...
bubu Posted October 24, 2006 Report Share Posted October 24, 2006 Galvu esi apspiedis, Robi? Link to comment Share on other sites More sharing options...
Recommended Posts