php e large bzip file

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

php e large bzip file

Messaggio da ZeroUno »

Salve.
Ho un sito scritto in phb e mi ritrovo con una problematica.
Sul sistema ci sono file di testo bzippati che il mio script deve leggere riga per riga.

per bzip non esiste un equivalente di fgets che uso per i file normali.

Una soluzione che adotto è quella di scompattare il file in uno temporaneo e leggere da quello.
La soluzione non mi piace per niente.

Poi questi file possono essere anche abbastanza grandi, e sul mio filesystem non posso mettere file più grandi di 8M (inutile dire che non li posso mettere nemmeno in ram dentro una variabile).

L'unica soluzione che mi viene in mente è quella di utilizzare una variabile buffer e utilizzarla a mo' di pipe. qualcosa tipo

Codice: Seleziona tutto

{
$buf=bzread($bz,4096);
preleva i caratteri da 0 al primo \n da $buf ed eliminali da $buf
ripeti finchè non ci sono più \n
} ripeti finchè il file non è finito
Secondo voi funziona. La soluzione non è molto bella.
Voi ne avete altre?
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
teox99
Linux 3.x
Linux 3.x
Messaggi: 738
Iscritto il: ven 25 lug 2008, 14:54
Slackware: 13.37
Desktop: KDE - Xfce
Località: Roma[Eur]
Contatta:

Re: php e large bzip file

Messaggio da teox99 »

ZeroUno ha scritto:La soluzione non è molto bella.
veramente è il problema che non è molto bello!

non puoi estrarre un file alla volta?

ilmich
Master
Master
Messaggi: 1645
Iscritto il: lun 16 lug 2007, 17:39
Slackware: 15.0 64bit
Kernel: 5.15.27
Desktop: kde
Località: Roma

Re: php e large bzip file

Messaggio da ilmich »

oddio.. perche' dite che non e' molto bella?!?!? in fondo con molta probabilita' fgets e' cosi' che funziona al suo interno.

Se proprio vuoi fare una cosa senza troppi controlli sul newline, puoi usare bzread con un buffer di lettura di un carattere.
Quando becchi il newline spezzi la linea e vai avanti.

Non ti so dire pero' se e quanto sta cosa possa pesare a livello di performance.
#LiveSimple and #ProgramThings
https://github.com/ilmich
http://ilmich6502.it/

ilmich
Master
Master
Messaggi: 1645
Iscritto il: lun 16 lug 2007, 17:39
Slackware: 15.0 64bit
Kernel: 5.15.27
Desktop: kde
Località: Roma

Re: php e large bzip file

Messaggio da ilmich »

Non si finisce mai di imparare :D
Ho scoperto una nuova funzione.. che fra l'altro risulta piu' veloce della stessa fgets.

Codice: Seleziona tutto

$fp=bzopen('test.bz2','r');
	
	$line=stream_get_line($fp,1024);
	do {
		echo $line; 
		$line=stream_get_line($fp,1024);
	} while(!feof($fp));	
	
	bzclose($fp);
Vedi se va bene ai tuoi scopi.
Ciau
#LiveSimple and #ProgramThings
https://github.com/ilmich
http://ilmich6502.it/

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: php e large bzip file

Messaggio da ZeroUno »

miklos ha scritto:stream_get_line($fp,1024);
eccola la funzione che cercavo; eppure ho girato e rigirato.
risulta piu' veloce della stessa fgets.
hai fatto test di performance?
puoi usare bzread con un buffer di lettura di un carattere.
... Non ti so dire pero' se e quanto sta cosa possa pesare a livello di performance.
un bel po', credo.

Considera che ho il max execution time a 10 secondi e in tale tempo devo scaricare un bz2 grande anche 3.8M, che decompresso ne sono 56, elaborarlo e buttarlo in un database. Fortunatamente i 10 secondi sono al netto di operazioni di I/O (mi sembra).
La vedo dura, ma se ci riesco ho svoltato.

Comunque se la stream_get_line va in porto con alte performance rimodifico tutto l'algoritmo di gestione file (che fortunatamente ho modularizzato e astratto in una classe).
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

ilmich
Master
Master
Messaggi: 1645
Iscritto il: lun 16 lug 2007, 17:39
Slackware: 15.0 64bit
Kernel: 5.15.27
Desktop: kde
Località: Roma

Re: php e large bzip file

Messaggio da ilmich »

ZeroUno ha scritto: hai fatto test di performance?
io no.. ma lui si e la differenza mi pare abissale :D
puoi usare bzread con un buffer di lettura di un carattere.
... Non ti so dire pero' se e quanto sta cosa possa pesare a livello di performance.
in effetti era abbastanza spudorata come proposta:)
ZeroUno ha scritto: Considera che ho il max execution time a 10 secondi e in tale tempo devo scaricare un bz2 grande anche 3.8M, che decompresso ne sono 56, elaborarlo e buttarlo in un database. Fortunatamente i 10 secondi sono al netto di operazioni di I/O (mi sembra).
dipende.. su windows e' il tempo reale.. su linux invece sei piu' fortunato perche' non contano le syscall e altre cose.. vedi il manuale di php alla voce set_time_limit per ulteriori dettagli(io ci ho sbattuto la testa un po' di tempo fa su sta cosa).
ZeroUno ha scritto: La vedo dura, ma se ci riesco ho svoltato.
piu' che altro perche' il collo di bottiglia mi pare stia nello scaricamento e nella memorizzazione nel database..
potresti avere piu' chance(e ti parlo non conoscendo quello che devi fare) se mentre leggi linea per linea prepari una catena di insert(magari a lotti) in modo da ridurre le connessioni al database e al tempo stesso inserire piu' righe possibile.
ZeroUno ha scritto: Comunque se la stream_get_line va in porto con alte performance rimodifico tutto l'algoritmo di gestione file (che fortunatamente ho modularizzato e astratto in una classe).
Ottimo
#LiveSimple and #ProgramThings
https://github.com/ilmich
http://ilmich6502.it/

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: php e large bzip file

Messaggio da ZeroUno »

miklos ha scritto:piu' che altro perche' il collo di bottiglia mi pare stia nello scaricamento e nella memorizzazione nel database..
potresti avere piu' chance(e ti parlo non conoscendo quello che devi fare) se mentre leggi linea per linea prepari una catena di insert(magari a lotti) in modo da ridurre le connessioni al database e al tempo stesso inserire piu' righe possibile.
Sono fiducioso perchè il problema l'ho già trattato in passato.
Questo script è passato da un server su cui il limite era più alto di 10 secondi.
Inizialmente lo script falliva perchè facevo una insert per ogni riga (era chiaramente troppo)
insert into tabella (campo,campo) values (val1,val2);
Poi una insert ogni blocco;
insert into tabella (campo;campo) values (val1,val2),(val3,val4).... ;
purtroppo i blocchi hanno dimensioni variabili, e qualche volta sono sufficientemente grandi da saturare la memoria a disposizione per php; tuttavia quando non si saturava le performance erano alte.
Alla fine ho trovato un compromesso.
Ho astratto la insert creando un buffer.
quando lancio una funzione insert() non mi viene sparata nel db ma in una variabile che mi funge da buffer. Alla seconda insert si accoda a questo buffer. Quando il buffer arriva al limite consentito, questo mi viene flushato nel db.
In questo modo il mio script su un server con limite a 30 secondi mi riusciva a scaricare ed inserire almeno una 50ina di file da 500K non compressi (che per quanto piccoli vanno scaricati) e una 20ina di file più grandi in bz2 (di cui la metà superano 1M, compresso).
Tutta l'operazione mi durava più di qualche minuto, ma non è mai fallita (evidentemente il tempo di elaborazione è abbastanza trascurabile rispetto al tempo di download ed insert).

Volevate qualche dettaglio maggiore sull'utilizzo che devo farne?
ok, eccolo: http://slak.homelinux.org
Attualmente residente su un server che mi da solo 100M di db (ne ho bisogno di minimo 800 per ottenere tutte le funzionalità), in passato residente su un server di mia gestione (100G di db mi bastavano :-) ), in fase di spostamento su un server che mi da 1.5G di db ma 10s di tempo di esecuzione.
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: php e large bzip file

Messaggio da ZeroUno »

Devo risparmiare prezioni millisecondi.

La soluzione dello stream_get_line sembra funzionare ma al momento mi si interrompe per maximum execution time a 280.000 record inseriti.
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

ilmich
Master
Master
Messaggi: 1645
Iscritto il: lun 16 lug 2007, 17:39
Slackware: 15.0 64bit
Kernel: 5.15.27
Desktop: kde
Località: Roma

Re: php e large bzip file

Messaggio da ilmich »

Immaginando che stiamo parlando di mysql, che tu abbia degli indici in tabella e che non usi un engine transazionale, prova a lockare la tabella.
Una roba del tipo

Codice: Seleziona tutto

LOCK TABLES nometabella WRITE;
INSERT INTO nometabella values(pippo,pluto);
...... ....
UNLOCK TABLES;
in questo modo le insert che fai su una tabella con degli indici sono piu' rapide in quanto gli indici vengono salvati una volta sola e dopo che sono state eseguite le insert all'interno del blocco LOCK/UNLOCK
#LiveSimple and #ProgramThings
https://github.com/ilmich
http://ilmich6502.it/

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: php e large bzip file

Messaggio da ZeroUno »

Fino a quando ero sul mio server andavo col transazionale, così se mi falliva la creazione andavo di rollback. Ma a quanto pare questo webhosting non lo supporta.
Comunque ci ho pensato che mi potesse rallentare.
L'ho tolto e infatti non mi ha cambiato la vita.
Il lock lo proverò (ammesso di averne i diritti) e vediamo cosa succede.

Una cosa ho notato.
Ho provato a modificare la dimensione del buffer delle insert che ho descritto sopra. Prima era 100k. portandolo a 1M lo script fallisce (perchè supera i 10 secondi) dopo x record. abbassandolo a 10k i dati vengono inseriti più lentamente (e il tempo totale lievita alquanto) ma fallisce dopo y record in cui y>x (e a volte non di poco) così in qualche caso riesce a terminare (il caso in oggetto però ha più di 30000 record e mai ce l'ha fatta, ma ci si sono avvicinati). C'è da dire poi che il server non è tra i più veloci. Ieri ho anche trovato qualche disservizio: "server too busy, try later" oppure errore mysql "shutdown server in progress".
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: php e large bzip file

Messaggio da ZeroUno »

Niente da fare.
Ho provato un po' tutte le combinazioni.
Il lock non so se gli è piaciuto o meno (magari per i diritti).
Sta di fatto che comunque fallisce per timeout.
Ho provato ad eliminare completamente gli indici, la chiave primaria e il campo autoincrement, ma fallisce ugualmente.
Comunque non credo che un problema di performance del db potrebbe inficiare. Infatti il db è considerato I/O e quindi non comporta cicli di clock che vengono rubati ai 10secondi di php.
Quello che tocca analizzare è il codice. Devo scoprire quale parte ruba preziosi millisecondi (mi sarebbe utile qualcosa tipo un ps che mostri l'effettivo uso della cpu ad un momento dato, in modo da inserire un po' di debug; non so se ho la funzione 'system' o 'exec' abilitate, ma ho alti dubbi. (a proposito... info sul server le trovate all'indirizzo http://server39.000webhost.com/phpinfo.php)
Altrimenti rimane la soluzione che non mi piace. Effettuare l'inserimento con più chiamate php sequenziali, ma questo comporta non pochi problemi, tipo il metodo per scoprire (il più velocemente possibile, altrimenti tutto inutile) dove si era rimasti, e il problema di riscrivere una buona fetta di codice.
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

ilmich
Master
Master
Messaggi: 1645
Iscritto il: lun 16 lug 2007, 17:39
Slackware: 15.0 64bit
Kernel: 5.15.27
Desktop: kde
Località: Roma

Re: php e large bzip file

Messaggio da ilmich »

Il seguente e' un trucchetto non ben 'documentato' che puo' darti una mano a rosicchiare millisecondi.
In pratica sostituisci dove possibile i doppi apici con gli apici singoli quando tratti le stringhe.
In soldoni visto che in php e' lecito

Codice: Seleziona tutto

    $nome = 'michele';
    echo "Ciao $nome"; //output Ciao michele
l'interprete php fa piu' passaggi quando si trova di fronte ad una stringa con i doppi apici perche' controlla pure se ci sono variabili e ne copia il valore.
Inoltre io lo faccio di mio ma scrivere

Codice: Seleziona tutto

 if (isset($array) && is_array($array)) {
    .....
 }
e' piu' veloce di scrivere

Codice: Seleziona tutto

  if (is_array($array)){
  ......
 }
sono trucchetti che non ti svoltano la vita, anche se su grossi loop o codice complesso la differenza la inizi a vedere.
Per ulteriori trucchetti guarda qui

Per quanto riguarda il profiling se sviluppi in locale ti consiglio fortemente l'estensione xdebug

Putroppo stanno per finire le idee :)
Immagino pure che abbia tunato lo schema del database (char dove possibile al posto dei varchar, provato con il partizionamento applicativo oppure quello automatico di mysql, ammesso che te lo facciano fare)

La sfida e' difficile in un ambiente come quello che hai tu.. pero' sono convinto che in qualche modo risolverai.
Fammi sapere perche' sono curioso 8)
#LiveSimple and #ProgramThings
https://github.com/ilmich
http://ilmich6502.it/

ilmich
Master
Master
Messaggi: 1645
Iscritto il: lun 16 lug 2007, 17:39
Slackware: 15.0 64bit
Kernel: 5.15.27
Desktop: kde
Località: Roma

Re: php e large bzip file

Messaggio da ilmich »

Io ho un dominio gratuito su 000webhost(non so se il tuo e' altresi' gratuito) e ho fatto questa prova che sembra funzionare :D
Edita( crealo se non ne hai uno) il file .htaccess e aggiungici questa riga:

Codice: Seleziona tutto

php_value max_execution_time 60
a me il tempo massimo di esecuzione e' cambiato :D
Non so quanto sia 'regolare' anche se non ho trovato sul forum di assistenza del servizio nulla che vieta categoricamente questa pratica.
#LiveSimple and #ProgramThings
https://github.com/ilmich
http://ilmich6502.it/

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: php e large bzip file

Messaggio da ZeroUno »

miklos ha scritto:Io ho un dominio gratuito su 000webhost(non so se il tuo e' altresi' gratuito) e ho fatto questa prova che sembra funzionare :D
Edita( crealo se non ne hai uno) il file .htaccess e aggiungici questa riga:

Codice: Seleziona tutto

php_value max_execution_time 60
a me il tempo massimo di esecuzione e' cambiato :D
naaaaaa, daiii, non ci credoooo.
Possibile che non se ne sono mai accorti?

Comunque si, ho l'account gratuito su 000webhost, e così funziona.


Certo che la sfida ormai mi è venuta.
A questo punto non so se dare precedenza alla stesura del progetto o alla sfida dei 10sec


@miklos,
sul char<->varchar mi sembra che ne ho parlato in passato da qualche parte.
Il char mi aumenterebbe decisamente le prestazioni nelle ricerche ma non è fattibile un char perchè mi verrebbe una tabella troppo grande in dimensioni (e già ci sto stretto). La dimensione delle stringhe da mettere è piccola di solito, ma esistono anche eccezioni piuttosto lunghe, e non posso permettermi di troncare. Inoltre nel caso in esame ormai credo che sia stato appurato che la velocità della singola query non inficia sui 10secondi a disposizione.
Il partizionamento ne ho sentito parlare ma non so cosa sia (google aiuta, ma non a quest'ora ;-) )
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: php e large bzip file

Messaggio da ZeroUno »

Questa è carina...
poco fa durante uno di questi test, una query fallisce:

["lastquery"]=> string(34) "DROP TABLE IF EXISTS slak_filelist"
["errno"]=> int(1053)
["error"]=> string(27) "Server shutdown in progress"

pochi minuti dopo mi arriva una mail:
We have detected that your account executing a slow MySQL queries.

MySQL Query: drop table if exists slak_filelist

Slow MySQL queries are not allowed, because you share server resources with thousands of other users and your long lasting MySQL queries are slowering the server and other users are having MySQL performance and connectivity problems. Please optimize your MySQL queries as soon as possible.
Here are some good articles how to optimize MySQL queries: http://www.google.com/search?q=optimize+mysql+queries

Good tips how you can optimize your scripts and make our servers run faster:
- Disable all parts of your website that allows anonymous posting, such as open forums, guestbooks. These days automated software fills all open areas of web with junk and content spam and increasing your database size.
- Disable visitors monitoring and tracking (each move of your visitor makes database query)
- Disable all unused modules
- Disable internal stats for your website - use http://www.google.com/analytics/ for example
- You may also logon to the phpMyAdmin and check which table has the most records. Then, if you think that this table does not contain any valuable information (such as logs, stats or cache), you can click on the `Empty` or `Truncate` icon to clean it.

We thank you for understanding,
www.000webhost.com
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Rispondi