2014-11-10 17 views
5

... sull'altro lato se scrivo qualcosa nelle pipe prima di aprire quella successiva, ciò non accade.Quando si aprono n pipe a processi figlio che eseguono xargs da Perl, i processi n-1 ricevono una riga vuota

Il seguente codice dovrebbe rendere più chiaro:

sub test_concurrent_pipes 
{ 
    my $write_at_once = $_[0]; 
    my $pipe_handle; 
    my @pipe_handle_list; 
    my $i; 
    foreach $i (1..3) 
    { 
     open ($pipe_handle, "| xargs echo") or die ("Cannot open pipe.\n"); 
     if ($write_at_once == 1) 
     { 
      print $pipe_handle "Hello\n"; 
     } 
     push(@pipe_handle_list, $pipe_handle); 
    } 
    foreach $pipe_handle (@pipe_handle_list) 
    { 
     print $pipe_handle "world\n"; 
    } 
    foreach $pipe_handle (@pipe_handle_list) 
    { 
     close ($pipe_handle); 
    } 
} 

print "Test 0: open all pipes before writing\n"; 
test_concurrent_pipes(0); 

print "Test 1: write Hello before opening next pipe\n"; 
test_concurrent_pipes(1); 

L'esecuzione del test ottengo

./test_pipe_2_xargs.pl 
Test 0: open all pipes before writing 


world world world 
Test 1: write Hello before opening next pipe 
Hello 
Hello 
Hello world world world 

Come si può vedere in Test 0, aprendo i 3 tubi di fila senza alcun output in tra genera 2 linee vuote. Stranamente, se sostituisco xargs echo con cat - non ci sono linee vuote prodotte. Il comportamento degli xargs sembra anche contraddire la sua pagina man, che afferma Blank lines on the standard input are ignored.

Come posso evitare quelle linee vuote?

Questo succede con Perl 5.14.2 su cygwin/XP e con Perl 5.8.8 su HP-UX 11.00.

scrivo quello che sto davvero cercando di fare alla fine, dal momento che è irrilevante in questa sede:

efficiente di pulizia tutti gli oggetti derivati ​​visibile da tutte le viste ClearCase attraverso uno script Perl che si biforca un unico processo per view per rimuovere il file (xargs rm) prima di rimuoverli dai VOB (rmdo).

+1

Ben fatto per fornire un esempio completo. – Sobrique

risposta

3

Fare "ciclo di creazione" utilizzare la variabile locale (my $pipe_handle) risolve il problema.

foreach $i (1..3) 
{ 
    open (my $pipe_handle, "| xargs echo") or die ("Cannot open pipe.\n"); 
    ... 
} 
+0

Ti voterò se spieghi perché in 3 frasi o meno :-) –

+0

Combinando la tua risposta con la nota di @ fjardon riguardo la documentazione 'open()' il mio rapido "grok" è che l'ambito con 'my' equivale ad avere '$ pipe_handle' non è definito al momento viene chiamato' open'. –

+0

Qualunque ambito con 'my' è locale al blocco di codice corrente. Nella Q è al di fuori del 'foreach' quindi viene riutilizzato - e quindi il prossimo 'open' lo sta sbagliando. – Sobrique

2

Apparentemente open sovrascritto il FILEHANDLE puntato da $pipe_handle, rendendo tutti i riferimenti in @pipe_hanlde_list punti per l'ultima canna aperta.

La documentazione afferma che $pipe_handle dovrebbe essere undefined quando si chiama open() ...

1

non contraddire la risposta di cui sopra, ma credo che stai andando su questo un modo strano. Perché hai bisogno di concatenare qualcosa?

Non penso che in realtà tu abbia alcun parallelismo: stai semplicemente alimentando una pipe in modo asincrono. In particolare con cose come rm, a cui si allude: il fattore limitante non sarà quasi mai i processi e la CPU, e piuttosto sarà l'IO del disco.

Nel tuo esempio sopra - stai costruendo liste di file in xargs in modo asincrono, ma in realtà non farà nulla con il comando finché il descrittore di file non è close ed. Se non stavi cercando di fare l'I/O del filesystem, ti suggerirei di usare il threading o la forking, ma lo scollegamento dei file non si sovrappone particolarmente bene.

0

Grazie a Filip per aver dato la risposta giusta ea fjardon e Sobrique per individuare la fonte del problema.

Dopo aver attraversato la documentazione open funzione ed alcuni test ho capito che si può operare in due modi: - sia il manico non è definita, nel qual caso si crea uno nuovo - o l'argomento maniglia è uno scalare, che diventa il nome della maniglia. Trovo particolarmente interessante l'esempio nella documentazione aperta in cui i file di codice C vengono aperti in modo ricorsivo quando si incontra una direttiva #include e sono assegnati a handle di file numerati (fh<nn> nella funzione process).

Quindi nel mio caso ogni open clubbers (e chiude) l'handle precedentemente aperto (tranne che per la prima chiamata). Pertanto l'elenco contiene tre handle per la stessa pipe. Nota: poiché stavo usando use strict mi sarei aspettato che Perl si lamentasse dell'uso di riferimenti simbolici (strict refs genera errori di runtime quando si usano riferimenti simbolici).

@Sobrique: come nota a margine, dopo aver corretto lo script reale e eseguito alcuni benchmark, risulta che eseguire i comandi in parallelo fa la differenza. Per il benchmark ho convogliato 700 nomi di file su uno xargs cleartool ls in 17 viste e l'ho eseguito il 37% più velocemente (in tempo reale) quando eseguito in parallelo. Questo è probabilmente correlato al fatto che un processo è in esecuzione per visualizzazione, Clearcase caching e Clearcase internals non correlati a IO. Ma non voglio iniziare una discussione sulle prestazioni qui, il problema principale è stato compreso e risolto. Grazie a tutti, ho apprezzato ogni input.