Как я могу выполнить системную команду в Perl асинхронно? - PullRequest
10 голосов
/ 18 ноября 2009

В настоящее время у меня есть Perl-скрипт, который выполняет внешнюю команду в системе, собирает выходные данные и выполняет некоторые действия в зависимости от того, что было возвращено. Прямо сейчас, вот как я запускаю это (где $ cmd - строка с командой setup):

@output = `$cmd`;

Я бы хотел изменить это так, что если команда зависает и не возвращает значение через столько времени, я убиваю команду. Как бы я запустил это асинхронно?

Ответы [ 3 ]

12 голосов
/ 18 ноября 2009

Существует множество способов сделать это:

  • Вы можете сделать это с помощью вилки (perldoc -f fork)
  • или используя потоки (потоки perldoc). И то, и другое затрудняет передачу возвращенной информации в основную программу.
  • В системах, которые его поддерживают, вы можете установить будильник (perldoc -f alarm), а затем очистить его в обработчике сигнала.
  • Вы можете использовать цикл обработки событий, такой как POE или Coro.
  • Вместо обратных галочек вы можете использовать open () или соответственно open2 или open3 (см. IPC :: Open2, IPC :: Open3), чтобы запустить программу при получении ее STDOUT / STDERR через дескриптор файла. Запустите на нем неблокирующие операции чтения. (perldoc -f select и, вероятно, Google "чтение неблокирующего perl")
  • В качестве более мощного варианта openX () проверьте IPC :: Run / IPC :: Cmd.
  • Вероятно, тонны, о которых я не могу думать посреди ночи.
8 голосов
/ 18 ноября 2009

Если вам действительно нужно установить тайм-аут для данного системного вызова, это намного более простая проблема, чем асинхронное программирование.

Все, что вам нужно, это alarm () внутри блока eval ().

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

/ bin / sleep 2 fail: время ожидания на ./time-out строка 15.

$ cat time-out
#!/usr/bin/perl

use warnings;
use strict;
my $timeout = 1;
my @cmd = qw(/bin/sleep 2);
my $response = timeout_command($timeout, @cmd);
print "$response\n" if (defined $response);

sub timeout_command {
        my $timeout = (shift);
        my @command = @_;
        undef $@;
        my $return  = eval {
                local($SIG{ALRM}) = sub {die "timeout";};
                alarm($timeout);
                my $response;
                open(CMD, '-|', @command) || die "couldn't run @command: $!\n";
                while(<CMD>) {
                        $response .= $_;
                }
                close(CMD) || die "Couldn't close execution of @command: $!\n";
                $response;
        };
        alarm(0);
        if ($@) {
                warn "@cmd failure: $@\n";
        }
        return $return;
}
1 голос
/ 18 ноября 2009

Если ваша внешняя программа не принимает никаких данных, поищите следующие слова в справочной странице perlipc:

Вот безопасный пробок или открытый канал для чтения:

Используйте пример кода и защитите его с помощью будильника (который также объясняется в perlipc).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...