2014-11-10 3 views
5

... с другой стороны, если я пишу что-то в трубах, прежде чем открывать следующую, этого не произойдет.При открытии n каналов дочерним процессам, выполняющим xargs из Perl, процессы n-1 получают пустую строку

Следующий код должен сделать его более ясным:

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

Запуск теста я получаю

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

Как вы можете видеть в тесте 0, открывая 3 трубы подряд без выхода в между генерирует 2 пустые строки. Как ни странно, если я подменю xargs echo на cat -, то не будет выпущено пустых линий. Поведение xargs также противоречит его странице руководства, в которой говорится: Blank lines on the standard input are ignored.

Как я могу избежать этих пустых строк?

Это происходит с Perl 5.14.2 на cygwin/XP и с Perl 5.8.8 на HP-UX 11.00.

Я пишу то, что я на самом деле пытаюсь сделать в конце, так как это не имеет значения здесь:

эффективны очистки всех полученных объектов, видимые со всех ClearCase взглядов через скрипт на Perl, который разветвляется один процесс в целях удаление файлы (xargs rm), прежде чем удалять их из VOB (rmdo).

+1

Хорошо сделано, поставляя полный пример. – Sobrique

ответ

3

Создание «цикла создания» с использованием локальной переменной (my $pipe_handle) устраняет проблему.

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

Я буду проголосовать за вас, если вы объясните, почему в 3 предложениях или менее :-) –

+0

Сочетание вашего ответа с примечанием @ fjardon относительно 'open()' документации моего быстрого «grok» заключается в том, что определение области с помощью 'my' эквивалентно '$ pipe_handle' не определено в момент вызова' open'. –

+0

Все, что связано с 'my', является локальным для текущего блока кода. В Q он находится вне 'foreach', поэтому он повторно используется, и, таким образом, следующий« открытый »сбивает его. – Sobrique

2

Видимо open переписал FILEHANDLE указывает $pipe_handle, что делает все ссылки в @pipe_hanlde_list пунктов до последней открытой трубы.

В документации говорится, что $pipe_handle должно быть определены при вызове open() ...

1

не противоречащий ответа выше, но я думаю, что вы собираетесь об этом как-то странно. Зачем вам нужно что-то параллельно?

Я не думаю, что вы на самом деле получаете какой-либо параллелизм - вы просто асинхронно питаете трубу. В частности, с вещами вроде rm, хотя вы намекаете - ваш лимитирующий фактор почти никогда не будет процессом и процессором, и скорее это будет диск IO.

В приведенном выше примере вы строит списки файлов в xargs асинхронно, но на самом деле ничего не будет делать с командой до тех пор, пока дескриптор файла не будет close ed. Если вы не хотите делать файловую систему ввода-вывода, я предлагаю использовать потоки или forking, но открепляющие файлы не очень хорошо распараллеливаются.

0

Спасибо Filip за то, что вы дали правильный ответ, а fjardon и Sobrique за то, что указали источник проблемы.

После прохождения функции документации open и некоторых тест я понимаю, что он может работать в двух направлениях: - либо ручка не определена, в этом случае он создает новый - или ручку аргумента является скаляром, который становится именем дескриптора. Я нахожу особенно интересным пример в открытой документации, где файлы кода C открываются рекурсивно при встрече с директивой #include и назначаются нумерованным файлам (fh<nn> в функции process).

В моем случае каждый open клабберов (и закрывает) ранее открытый дескриптор (за исключением первого вызова). Поэтому список содержит три ручки для одного и того же канала. Примечание: поскольку я использовал use strict, я бы ожидал, что Perl будет жаловаться на использование символических ссылок (strict refs генерирует ошибки времени выполнения при использовании символических ссылок).

@Sobrique: в качестве побочного примечания, после исправления реального скрипта и выполнения бенчмаркинга, оказывается, что выполнение параллельных команд действительно имеет значение. Для сравнения я подал 700 имен файлов на xargs cleartool ls, работающий на 17 просмотров, и сделал это на 37% быстрее (в реальном времени) при параллельном выполнении. Скорее всего, это связано с тем, что один процесс работает на просмотр, кэширование Clearcase и внутренние элементы Clearcase, не связанные с IO. Но я не хочу начинать дискуссию о производительности здесь, основная проблема была понята и решена. Спасибо всем, я оценил каждый вход.