Процессы как файловые дескрипторы

До настоящего момента рассматривался исключительно синхронный запуск процессов, когда Perl заправляет всем происходящим, запускает команду, (обычно) дожидается ее завершения и получает вывод. Но Perl также может запускать дочерние процессы, которые существуют самостоятельно и взаимодействуют с Perl на долгосрочной основе вплоть до завершения задачи. В синтаксисе запуска параллельного дочернего процесса команда задается в качестве «имени файла» при вызове open, а перед или после нее ставится вертикальная черта. Этот синтаксис часто называется открытием канала:

open DATE, "date|" or die "cannot pipe from date: $!";
open MAIL, "|mail merlyn" or die "cannot pipe to mail: $!";

В первом примере, когда символ | стоит справа, стандартный вывод запущенной команды связывается с файловым дескриптором DATE, открытым для чтения, по аналогии с выполнением date | your_program в командном процессоре. Во втором примере, когда символ | стоит слева, стандартный ввод команды соединяется с дескриптором MAIL, открытым для записи, по аналогии с командой your_program | mail merlyn. В обоих случаях команда продолжает работать независимо от процесса Perl. Если создать дочерний процесс не удалось, вызов open завершается неудачей.


Если команда не существует или некорректна, это (обычно) не воспринимается как ошибка при открытии, но приводит к ошибке при закрытии. Вскоре мы вернемся к этому вопросу. Остальная часть программы не знает, что файловый дескриптор открыт для процесса, а не для файла – более того, это неважно, и чтобы узнать об этом, придется основательно потрудиться. Таким образом, чтобы получить данные из файлового дескриптора, открытого для чтения, достаточно выполнить обычную операцию чтения:

my $now = ;

А чтобы отправить данные процессу mail (ожидающему получить тело сообщения для merlyn в стандартном вводе), хватит простой команды print с файловым дескриптором:

print MAIL "The time is now $now"; # Предполагается, что $now
# завершается символом новой строки

Короче говоря, вы можете считать, что эти дескрипторы связаны с «волшебными файлами»: один файл содержит вывод команды date, а другой автоматически передает данные команде mail. няет предыдущее значение, так что сохраните его побыстрее, если собираетесь использовать в будущем. (Переменная $? также содержит код завершения последней команды system или ` `, если вас это интересует.) Процессы синхронизируются точно так же, как цепочки конвейерных команд.


Если вы пытаетесь прочитать данные, а данные недоступны, процесс приостанавливается (без потребления дополнительного процессорного времени) до тех пор, пока программа-отправитель не «заговорит» снова.

Аналогично, если записывающий процесс «опередит» читающий процесс, он приостанавливается до тех пор, пока последний не «догонит» его. Между процессами создается промежуточный буфер обмена данными (обычно 8 Кбайт или около того), так что абсолютно точная синхронизация не требуется. Зачем связывать процессы с файловыми дескрипторами? Прежде всего, это единственный простой способ передачи данных процессу на основании результатов вычислений. При чтении данных обратные апострофы обычно гораздо удобнее, если только данные не должны обрабатываться сразу же после записи. Например, команда UNIX find ищет файлы по атрибутам и при относительно большом количестве файлов (например, при рекурсивном поиске от корневого каталога) выполняется сравнительно долго. Команду find можно выполнить в обратных апострофах, но часто бывает удобнее получать результаты по мере их поступления:

open F, "find / -atime +90 -size +1000 -print|" or die "fork: $!";
while () {
chomp;
printf "%s size %dK last accessed on %s\n",
$_, (1023 + -s $_)/1024, -A $_;
}

Команда find находит файлы, к которым не было обращений за последние 90 дней, превышающие размером 1000 блоков.


(Эти файлы являются хорошими кандидатами для перемещения на архивные носители.) В процессе поиска Perl ждет. При обнаружении очередного файла Perl реагирует на входящее имя и выводит информацию о файле для дальнейшего анализа. Если бы команда поиска выполнялась в обратных апострофах, мы бы не получили никаких данных до завершения find. Всегда полезно знать, что команда по крайней мере работает.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Perl на эту тему:
Ветвление
Выполнение команд в обход командного процессора
Обратные апострофы в списочном контексте
Обратные апострофы и сохранение вывода
Отправка и прием сигналов

Вернуться в раздел: Perl / 15. Управление процессами