attività di memoria e tempo intensivo di php

3

Scusa se questa domanda è stata già chiesta, ma non ho trovato nulla di utile.

Sto lavorando a un progetto per un cliente e attualmente devo scorrere la tabella degli utenti che è di circa 3000 record e ancora in crescita.

Devo fare alcuni calcoli su base notturna che userò cron / php. Lo script dei calcoli utilizza circa 3,5 MB di memoria e impiega circa 1 secondo per l'esecuzione.

Durante il caricamento di singoli utenti, la mia attuale configurazione php gestisce questa multa, ma se provo a scorrere l'elenco degli utenti il tempo di esecuzione dello script php si esaurisce.

Ho letto dopo aver effettuato alcune ricerche che posso ricaricare la pagina stessa dopo ogni calcolo utente e mantenere il mio precedente posto nel ciclo e questa mi sembra una buona idea, ma volevo sentire alcune opinioni degli altri che ho gestito situazioni simili e come hai gestito questi tipi di attività.

Grazie.

    
posta Goddard 07.07.2012 - 04:40
fonte

2 risposte

2

Se ti aspetti davvero che la tua tabella cresca, dovresti iniziare a pensare al batch del processo, a fare i tuoi calcoli in fasi. Il modo più semplice sarebbe avere una tabella secondaria che possa contenere l'id utente e il timestamp di quando l'utente è stato elaborato per l'ultima volta, e limitare lo script cron a scorrere, ad esempio, 500 utenti per volta. I numeri esatti dipenderanno da cosa stai facendo esattamente, sarà un po 'di prova ed errore.

Se decidi di eseguire il batch del processo, dovrai ovviamente eseguire lo script cron più di una volta, è abbastanza facile, elaborare solo utenti che non sono stati elaborati di recente (controllando il timestamp) e, ovviamente, registrarli come elaborati in seguito. Se i tuoi ID utente sono sequenziali, potresti risparmiarti la fatica di registrare ogni id utente elaborato e solo registrare l'ultimo del batch, tuttavia se qualcosa va storto nel mezzo del batch, non avresti alcuna idea di dove si fermò. La tua scelta;)

Quindi devi ottimizzare il tuo ciclo. Inizia con le cose semplici, stai usando o foreach? C'è un'abbondanza di riferimenti che sostengono che uno sia più veloce dell'altro, ma la verità è che dovrai metterli alla prova e scoprire quale è più veloce (se c'è davvero una differenza) per te. Dipende dalla tua versione php, os, e dalle strutture che stai eseguendo in loop (se stai eseguendo il loop di oggetti iterabili, per esempio), e ovviamente dovresti eseguire il test sul server in cui il tuo script vivrà, specialmente se l'ambiente è diverso da il tuo sviluppo locale.

Quindi, è il momento di profilare e ottimizzare i tuoi calcoli. Non ci stai dicendo cosa stai facendo, ma 3.5mb di memoria sembrano un po 'troppo per una singola iterazione. Potrebbe essere che i tuoi calcoli sono così intensi e hai fatto del tuo meglio, o potrebbe esserci qualcosa di ovvio che ti manca, in ogni caso è qualcosa che solo un profiler può dirti.

Sebbene max_execution_time sia hardcoded a 0 (nessun limite) per la SAPI della CLI, potresti voler limitare il tempo di esecuzione attraverso set_time_limit o ini_set ('max_execution_time') ( stessa cosa) per due motivi:

  1. Aiuterà a testare lo script tramite il browser, dove c'è un limite (in php.ini). Non sarebbe consigliabile consentire l'accesso del browser allo script di produzione, ma durante lo sviluppo non avrebbe senso impostare cron solo per testare il tuo script.
  2. Anche se non c'è limite per gli script CLI, non sarebbe male imporre il limite nel caso in cui qualcosa di sconveniente accadesse. I server di database rallentano di tanto in tanto e non si desidera realmente che lo script venga eseguito all'infinito (== finché non esaurisce la memoria).

Se hai problemi di memoria, è ora di fare qualche raccolta dei rifiuti . L'approccio ingenuo sarebbe quello di chiamare gc_collect_cycles alla fine del tuo script, forzando la garbage collection di tutti i cicli esistenti in quel momento. Non sarebbe male se hai unset () risorse di memoria affamate prima mano. Ricorda che i loop php non creano il proprio ambito, ad esempio:

<?php

foreach($array as $key => $value) {
   doSomething($value);
}

var_dump($key, $value);

?>

funzionerà, scaricando l'ultimo $key e $value del ciclo, il che significa che alla fine del ciclo non ne hai uno ( $array ) ma tre variabili inutilizzate, che verranno raccolte quando php decide che è un buon momento per raccogliere rifiuti. Per forzarlo, fai qualcosa come:

<?php

foreach($array as $key => $value) {
   doSomething($value);
}

unset($array, $key, $value);
gc_collect_cycles();

?>

Sono sicuro al 99% che unset($array, $key, $value); non sia necessario qui, tuttavia è un trucco preferito del < php 5,3 giorni, e lo sto rispettando (almeno fino a quando non comprenderò pienamente come funziona la garbage collection in php;).

Per qualcosa di più, devi davvero darci le specifiche dei tuoi calcoli e mostrarci il tuo codice.

    
risposta data 07.07.2012 - 17:07
fonte
2

La soluzione ingenua sarebbe aumentare l'impostazione del timeout della richiesta di PHP; c'è un'impostazione php.ini per questo.

Ma visto che stai lavorando a un cron job, mi chiedo perché hai un caricamento della pagina - dovresti eseguire il lavoro come php-cli, cioè da una riga di comando, senza alcuna funzionalità web a tutti (e quindi, anche al di fuori di apache). Per gli script CLI, non esiste un timeout (o almeno non ce n'è per l'impostazione predefinita, non è sicuro se è possibile imporne uno), e sulla maggior parte dei sistemi, la versione CLI utilizza il proprio php.ini, il che significa che puoi dare al tuo cron job dei limiti di memoria più generosi, se necessario.

Se usi php-cgi / mod_php / ..., dovrai eseguire il wrapping dello script in una chiamata curl o wget solo per poterlo inserire in un processo cron - questa è una soluzione goffa e anche insicuro, perché ora chiunque può inviare richieste alla tua applicazione può attivare il cron job - facile preda per gli attacchi DoS. Se invece usi php-cli, puoi eseguire lo script direttamente da cron: PHP consente anche una linea hash-bang ( #!/usr/bin/env php ), ma molto probabilmente, dovrai chiamare php esplicitamente, quindi puoi eseguire l'override php.ini e così.

    
risposta data 07.07.2012 - 09:31
fonte

Leggi altre domande sui tag