2011-01-23 4 views
8

Ho una funzione di utilità utilizzata per l'esecuzione di un programma tramite CLI (cmd, bash ecc.). Restituisce una serie di 3 articoli: STDOUT, STDERR e EXIT CODE.PHP apre più volte proc_open

Finora, ha funzionato bene senza problemi. In effetti, il problema che ho con esso non ostacola realmente la sua funzionalità, ma sono preoccupato per le prestazioni.

Il problema è che in alcuni casi, PHP esegue lo stesso comando più volte (3 volte nel mio caso), anche se si supponeva di farlo solo una volta.

/** 
* Executes a program and waits for it to finish, taking pipes into account. 
* @param string $cmd Command line to execute, including any arguments. 
* @param string $input Data for standard input. 
* @param boolean $log Whether to log execution failures or not (defaults to true). 
* @return array Array of "stdout", "stderr" and "return". 
*/ 
public static function execute($cmd,$stdin=null,$log=true){ 
    //static $once=true; if(!$once)die; $once=false; 
    $proc=proc_open($cmd, array(
     0=>array('pipe','r'), 
     1=>array('pipe','w'), 
     2=>array('pipe','w') ), $pipes); 
    fwrite($pipes[0],$stdin);    fclose($pipes[0]); 
    $stdout=stream_get_contents($pipes[1]); fclose($pipes[1]); 
    $stderr=stream_get_contents($pipes[2]); fclose($pipes[2]); 
    $return=proc_close($proc); 
    if($return!=0 && $log) 
     xlog('Error: Program execution returned failure.',$stdout,$stderr,$return); 
    return array('stdout'=>$stdout, 'stderr'=>$stderr, 'return'=>$return); 
} 

Prendere nota della riga commentata (riga 9). Questo era per i test. L'ho abilitato per garantire che il programma di destinazione venga eseguito una volta sola (stavo pensando che il mio codice potrebbe chiamare in qualche modo la stessa funzione). Ma anche con quella linea abilitata, il programma è ancora in esecuzione più volte.

Così com'è, ho 2 posizioni nel mio codice in cui sto eseguendo lo stesso programma (in diverse occasioni). La riga di comando è la stessa per entrambi.

Tuttavia, in un'occasione, il programma viene eseguito una volta, mentre nell'occasione, PHP esegue il programma 3 volte.

Ho monitorato e visualizzato questo comportamento in Process Explorer. Sto usando Windows 7 x64. Il programma è a 32 bit, così come PHP.

Modifica: Il programma in questione è personalizzato e non apre nuovi processi.

+4

utilizzare un altro strumento di processo per verificare l'osservazione. Non hai menzionato quale programma è (potrebbe sborsare in sottoprocessi da solo). – mario

+0

@Christian: come possiamo verificarlo? Come hai detto, non hai menzionato quale programma sia. Mario ha perfettamente ragione; dovresti ascoltarlo –

+0

Scusate, volevo dire "controllato" (ora ho cancellato il commento per evitare confusione). Quello che ho voluto dire è che l'ho controllato con Process Monitor. Edit: E l'ho ascoltato;) lol – Christian

risposta

1

Il codice per verificare che venga eseguito solo una volta sembra difettoso.

Se sono in esecuzione 2 processi php, non condivideranno una variabile statica. Quindi potrebbe essere possibile avere richieste simultanee che lo fanno funzionare più di una volta.

In secondo luogo, è necessario impostare $once su false alla fine della funzione, altrimenti lo die non verrà mai raggiunto.

Provare ad aggiungere alcune registrazioni per vedere se la funzione viene chiamata da due volte.

Creare alcuni test di unità/stress che eseguono solo l'applicazione esterna. Se vedi più processi, allora c'è qualcosa con la tua app che è sbagliata, non il codice php.

+0

Lo sto facendo localmente, quindi posso vedere ogni singola sessione e anche i processi che si aprono. Il programma viene eseguito una sola volta quando viene invocato da solo. Sono sicuro che la mia affermazione originale sia corretta. – Christian

+0

@Christian - Quando si aggiunge la registrazione alla funzione, sembra essere chiamata più volte o il processo stesso è stato avviato più volte da php windows o dall'app? –

+0

@ByronWhitlock: il processo stesso viene caricato più volte. Il codice commentato assicura che la funzione venga richiamata una sola volta. – Christian

0

È molto strano. Ed è molto difficile capire senza il codice completo.

Se si sta stressando il server chiamando la stessa pagina più volte, la mia scelta migliore è probabilmente legata al processo round robin della CPU. Il PHP non ha il tempo di impostare la variabile statica su false perché allo stesso modo c'è un'altra richiesta a questo metodo. Altra possibilità è che PHP non riesca a isolare correttamente il valore statico e la diversa richiesta a questo metodo può leggere diverse posizioni di memoria finché il PHP non sincronizza i valori.

0

So che questa potrebbe non essere l'opzione migliore, ma questo è quello che ho fatto. Anche se questo era su Linux, ma sono sicuro che ci sia modo di portarlo su Windows.

Quello che ho fatto è stato eseguire pgrep e verificare se esistesse già un comando come questo e se semplicemente uscisse. Come hai detto, stai eseguendo lo stesso comando (con parametri esatti), quindi controlla se c'è già un comando in esecuzione e agisci rispettivamente.

Ho usato questo comando:

$pid = shell_exec('pgrep -cfx "/* My command */"'); 
if ($pid > 1) return -1;