2014-11-10 4 views
5

... auf der anderen Seite ausgeführt wird, wenn ich etwas zu den Rohren schreiben, bevor die nächste Öffnung, dies nicht geschieht.Wenn n Rohre Kindprozesse öffnen xargs von Perl, n-1-Prozesse erhalten eine leere Zeile

Der folgende Code sollte es klarer machen: Ich bekomme

./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 

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); 

den Test Rennen Wie Sie in Test 0, das Öffnen der drei Rohre in einer Reihe ohne Ausgabe sehen in dazwischen erzeugt 2 leere Zeilen. Seltsamerweise, wenn ich xargs echo durch cat - ersetze, werden keine leeren Zeilen erzeugt. Das Xargs-Verhalten scheint auch seine man-Seite zu widersprechen, die besagt Blank lines on the standard input are ignored.

Wie kann ich diese leeren Zeilen vermeiden?

Dies geschieht mit Perl 5.14.2 auf Cygwin/XP und mit Perl 5.8.8 auf HP-UX 11.00.

ich schreiben, was ich wirklich bin versucht, am Ende zu tun, da es hier irrelevant ist:

effizient Bereinigung all abgeleiteten Objekte sichtbar aus allen Clearcase Ansichten über einen Perl-Skript, das Gabeln ein Prozess pro Ansicht die entfernen Dateien (xargs rm), bevor Sie sie aus den VOBs (rmdo) entfernen.

+1

Gut gemacht bei der Lieferung eines vollständigen Beispiels. – Sobrique

Antwort

3

Positionen "Schaffung loop" lokalen Variable verwenden (my $pipe_handle) behebt das Problem.

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

Ich werde dich abstimmen, wenn du erklärst, warum in 3 Sätzen oder weniger :-) –

+0

Kombiniere deine Antwort mit @fjardons Anmerkung bezüglich der 'open()' Dokumentation mein schnelles "grok" ist, dass Scoping mit 'my' äquivalent zu haben ist '$ pipe_handle' ist in dem Moment nicht definiert, in dem' open' aufgerufen wird. –

+0

Alles, was mit 'my' versehen ist, ist lokal für den aktuellen Codeblock. Im Q ist es außerhalb der 'foreach', so dass es wiederverwendet wird - und somit wird das nächste 'open' es verderben. – Sobrique

2

Offenbar überschrieben open die Dateihandle von $pipe_handle darauf, alle Verweise in @pipe_hanlde_list Punkten auf das neueste offene Rohr machen.

Die Dokumentation besagt, dass $pipe_handle sollte nicht definiert werden, wenn open() Aufruf ...

1

nicht die Antwort oben zu widersprechen, aber ich denke, Sie darüber eine seltsame Art und Weise fahren. Warum müssen Sie gleichzeitig alles pipen?

Ich glaube nicht, dass du eigentlich jede Parallelität bekommen - Sie nur asynchron ein Rohr zugeführt wird. Besonders mit Dingen wie rm, auf die Sie anspielen - Ihr limitierender Faktor wird fast nie die Prozesse und CPU sein, und es wird eher die Disk IO sein.

In Ihrem Beispiel oben - Sie erstellen Dateilisten in Xargs asynchron, aber es wird nichts mit dem Befehl tun, bis der Dateideskriptor close ed ist. Wenn Sie nicht nach Dateisystem-IO suchen, würde ich vorschlagen, Threading oder Forking zu verwenden, aber die Verknüpfung von Dateien lässt sich nicht besonders gut parallelisieren.

0

Dank Filip für die richtige Antwort zu geben und fjardon und Sobrique für die Ursache des Problems ausfindig.

Nachdem man durch die open Funktion Dokumentation und einige Tests, die ich verstehe, dass es auf zwei Arten arbeiten: - entweder der Griff nicht definiert ist, in welchem ​​Fall es ein neuen schafft - oder den Griff Argument ist ein Skalar der wird der Name des Griffs. Ich finde besonders interessant das Beispiel in der geöffneten Dokumentation, wo C-Code-Dateien rekursiv geöffnet werden, wenn eine Direktive #include auftritt und nummerierte Datei-Handles zugewiesen sind (fh<nn> in process Funktion).

Also in meinem Fall jeder open clubbers (und schließt) den zuvor geöffneten Griff (bis auf den ersten Anruf). Daher enthält die Liste drei Handles für dieselbe Pipe. Hinweis: Da ich use strict verwendet habe, hätte ich erwartet, dass Perl sich über die Verwendung symbolischer Referenzen beschweren würde (strict refs erzeugt Laufzeitfehler, wenn symbolische Referenzen verwendet werden).

@Sobrique: Als Nebenbemerkung, nach der Korrektur der realen Skript und einige Benchmarking, stellt sich heraus, dass die Ausführung der Befehle parallel macht einen Unterschied. Um Benchmarks habe ich 700 Dateinamen an eine xargs cleartool ls in 17 Ansichten piped und machte es 37% schneller (Echtzeit), wenn parallel ausgeführt. Dies hängt höchstwahrscheinlich damit zusammen, dass pro Ansicht ein Prozess ausgeführt wird, Clearcase-Caching und CLEARCASE-Interna, die nicht mit IO verknüpft sind. Aber ich möchte hier keine Diskussion über die Leistung beginnen, das Hauptproblem wurde verstanden und gelöst. Danke an alle, ich schätze jeden Input.