2014-12-18 15 views
7

È possibile avviare il loop da un certo punto?iteratore directory ricorsivo con offset

$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, $flags)); 

$startTime = microtime(true); 
foreach($iterator as $pathName => $file){ 

    // file processing here 

    // after 5 seconds stop and continue in the next request 
    $elapsedSecs = (microtime(true) - $startTime); 
    if($elapsedSecs > 5) 
    break; 
} 

Ma come si riprende dal punto di interruzione nella richiesta successiva?

+0

1. ripristinare il numero di articoli elaborati; se non è impostato, inizializzalo con zero; 2. inserire il ciclo, saltare il numero di articoli elaborati; 3. elaborare un articolo; 4. conta; 5. rompere il ciclo; 6. passare il valore alla richiesta successiva (utilizzando la sessione o la stringa di query). Risciacqua e ripeti. – axiac

risposta

2

a) estrarre il calcolo del tempo dal foreach. hai un'ora di inizio e vuoi un tempo di esecuzione di 5 secondi, in modo da poter calcolare l'ora di fine prima (startime + 5s). all'interno del foreach, semplicemente confrontare se il tempo è maggiore o uguale al tempo di conclusione, quindi interrompere.

b) D: è possibile avviare il loop da un certo punto? come riprendo dal punto di interruzione nella richiesta successiva?

Due approcci mi vengono in mente.

È possibile memorizzare l'ultimo punto di elaborazione e l'iteratore e riprendere all'ultimo punto + 1. Si salverà l'ultima posizione dell'iterazione e si avanza rapidamente alla successiva richiesta, chiamando iterator-> next() fino a raggiungere il prossimo oggetto da elaborare, che è $ lastPosition + 1. dobbiamo memorizzare l'iteratore e l'ultima posizione e prelevarli entrambi alla successiva richiesta, finché lastPosition è uguale al numero totale di elementi nell'iteratore.

Oppure, è possibile trasformare l'iteratore in una matrice alla prima esecuzione: $array = iterator_to_array($iterator); e quindi utilizzare un approccio di riduzione dell'array. (Forse qualcun altro sa come ridurre un oggetto iteratore.) Con questo approccio si potrebbe memorizzare solo i dati, che diminuisce richiesta su richiesta fino a 0.

Il codice è testato. È solo una bozza veloce.

$starttime = time(); 
$endtime = $starttime + (5 * 60); // 5sec 
$totalElements = count($array); 

for($i = 0; $i <= $totalElements; $i++) 
{ 
    if(time() >= $endtime) { 
     break; 
    } 

    doStuffWith($array[$i]); 
} 

echo 'Processed ' . $i . ' elements in 5 seconds'; 

// exit condition is "totalElements to process = 0" 
// greater 1 means there is more work to do 
if(($totalElements - $i) >= 1) { 

    // chop off all the processed items from the inital array 
    // and build the array for the next processing request 
    $reduced_array = array_slice(array, $i); 

    // save the reduced array to cache, session, disk  
    store($reduced_array); 
} else { 
    echo 'Done.'; 
} 

// on the next request, load the array and resume the steps above... 

Tutto sommato, questo è l'elaborazione in batch e può essere fatto in modo più efficiente da un lavoratore/lavoro-code, come:

+1

grazie, proverò Gearman. Ho pensato di archiviare l'array completo da qualche parte, ma in alcuni casi può raggiungere gli elementi di 200K, e sono abbastanza sicuro che richieda molte risorse in PHP –

Problemi correlati