[ Zdravko T1 @ 19.09.2010. 18:49 ] @
Pisao sam skriptu koja treba da otvori tekstualni dokument velicine 10MB i parsira dokument tako da odredjene vrednosti stavi u niz.Ono sto me muci je to sto skripta to ne moze uraditi bez memory_limit direktive stavljene na vrednost 256M, tj 256MB memorije posveceno PHP-u.
Jasno je da ovakvu skriptu ne mogu koristiti na shared hostinzima sto je bila prvobitna namera.Da li je PHP zaista toliko zahtevan za vece dokumente ili bi u ovakvim situacijama trebala neka optimizacija koda?
[ loonies @ 19.09.2010. 20:41 ] @
Koje f-je koristis za citanje fajla? Bilo bi dobro kada bi mogli da vidimo odgovarajuci kod.
[ Zdravko T1 @ 19.09.2010. 20:56 ] @
Naravno,

Code:

$lines = array();
// citanje fajla 
$handle = fopen($path, "r");
if ($handle) {
       while (!feof($handle)) {
               $lines[] = fgets($handle, 4096);
      }
           fclose($handle);
}
 // parsiranje
foreach($lines as $line) {
      $str = explode(",",$line);
      // dalja obrada vrednosti sa strpos(), substr()
}
[ Tudfa @ 19.09.2010. 23:57 ] @
Iz tog dela koda moze samo da se zakljuci da je utrosak oko 10 ili malo vise MB.
Verovatno ti je krivac za tu veliku potrebu za memorijom onaj deo za parsiranje...

Bez relevantnog koda, tesko da ce ti neko reci gde je "otislo" toliko memorije

A ovaj kod sto si prilozio mogao bi drugacije da se napise ako taj niz $lines koristis samo u toj foreach petlji.
Ako je to slucaj (mozda i nije,ne vidim ostatak koda) mogao bi parsiranje da uradis direktno nad stringom koji vrati fgets.

Time izbegavas upotrebu niza "teskog" 10 MB, ciju svrhu u ovom kodu koji si prilozio - ne vidim.
[ Zdravko T1 @ 20.09.2010. 01:50 ] @
U pravu si, ladno nisam zapazio da sam svo parsiranje mogao uraditi u while petlji i tu ustedeti dosta resursa.Evo sada sam svo procesiranje prebacio tu i OK radi.Hvala puno.
[ strutter.poison @ 20.09.2010. 02:12 ] @
Bas sam skoro nesto razmisljao na temu ovoga. Veliki fajl u array pa liniju po liniju procesirati. Kontam da se ovako oslobadja memorija za nove nizove, stingove koji se dobijaju tokom procesiranja.:

Code:
foreach ($lines AS &$line) {
    //uraditi nesto sa linijom
    $line = '';
}

ili

foreach ($lines AS $key=>&$value) {
    //ako ima ono sto nam treba
    $value = $obadjenaLinija;
    //ako nema
    unset($lines[$key]);
}

Jesam li u pravu?
[ peromalosutra @ 20.09.2010. 17:36 ] @
Kao sto Tudfa rece, najefikasnije je da uopste ne koristis niz, vec da svu obradu radis prilikom ucitavanja (pa u memoriji drzis samo trenutnu liniju).

Naravno, zavisi od toga sta ti treba, bez detalja se ne moze mnogo reci.
[ Zdravko T1 @ 21.09.2010. 00:30 ] @
Evo mene sa novim problemom...ne znam sta mi je ciniti, ako bi neko mogao da me upiti ne neki algoritam mnogo bih mu bio zahvalan, evo o cemu se radi

Kako sam resio da se reci procesiraju direktno u while petlji, sada bi trebao da u toj istoj while petlji uporedim dobijenu liniju sa dictionary fajlom od 1MB...Kako u faju koji parsiram ima oko 250 000 linija, to znaci da ce 250 000 puta dolaziti i obrada tog dictionary fajla od 1MB...Pokusao sam to na mom racunaru i izvrsavanje nije moglo u dogledno vreme da se zavrsi.Ako neko ne razume evo dacu primer:

Code:

$lines = array();
// citanje fajla 
$handle = fopen($path, "r");
// citanje dictionary file-a
$h = fopen($path2, "r");
if ($handle) {
       while (!feof($handle)) {
               $line = fgets($handle, 4096);
                  while (!feof($h)) {
                    $line2 = fgets($h, 4096);
            
                   if($line == $line2)
                      echo "success";
      }
             
      }
           fclose($handle);
}

to je odrpilike kod(ne pravi, vec na koji nacin se vrsi glavni deo), ima neko ideju za optimizaciju ?
[ Miroslav Ćurčić @ 21.09.2010. 02:09 ] @
uf, uf, uf,
ovde ti ne gine da recnik drzis u memoriji pa da ga poredis sa svakom linijom.

ako treba da poredis dugacke stringove probaj da ih sve konvertujes u hash-ove pa ga poredi sa hash-ovain linijama tekstualne datoteke, to moze da ubrza izvrsavanje
[ Goran Rakić @ 21.09.2010. 02:21 ] @
Učitaj "rečnik" u niz pre glavne petlje, koristi in_array() za iterativnu pretragu u petlji.

Za dodatne performanse mada verujem da ti to neće biti potrebno možeš da okreneš niz rečnika tako da podaci budu ključevi preko array_flip() čime dobijaš direktan pristup sa isset() u glavnoj petlji što ti tu daje . Obrati pažnju da ako imaš različite linije sa istim sadržajem, nakon array_flip() samo jedna se čuva u nizu, ali po tvom kodu ovo ti neće ni na koji način smetati. Izmeri da li to radi brže.

Ako ti to ipak smeta ili ovo radi sporije (ako je array_flip spor), možeš da napišeš svoju funkciju za pakovanje koja dok redove iz rečnika smešta tokom učitavanja kao ključeve u asocijativan niz, a redove sa istim sadržajem u podniz. Ili ako ne želiš da koristiš asocijativan niz na ovaj način, možeš da izbegneš iterativnu pretragu u in_array tako što po učitavanju sortiraš niz sa redovima iz rečnika preko sort() ili sortiraš datoteku unapred, i potom koristiš binarnu pretragu u glavnoj petlji što tu daje .

Ako ti prosto trebaju redovi koji su prisutni u obe datoteke, sortiraj obe i potom odradi upoređivanje premotavanjem. Dakle ako je trenutni red prve manji od druge, čitaš prvu, ako je veći čitaš iz druge, a ako je jednak imaš pogodak. Umesto sada imaš samo u glavnoj petlji. U memoriji se čuva samo po jedan red iz obe datoteke.


Moj komentar kao moderatora je da ako očekuješ korisne savete podeliš isečak iz pravog koda ili ako je ti to neki NDA dokument ne dozvoljava konstruišeš primer koji potpuno prati logiku koda koji sastavljaš. Ovako kada stalno ubacuješ nove elemente u zagonetku, niko ne može da ti stvarno pomogne i moraću da zaključam ovu temu. Na primer, siguran sam da si ovde imao u glavnoj petlji i neki fopen/fclose ili makar rewind() za $h, ali u tvom primeru toga nema.


[Ovu poruku je menjao Goran Rakić dana 21.09.2010. u 03:55 GMT+1]