Как запустить системную команду в Perl асинхронно?
в настоящее время у меня есть скрипт Perl, который запускает внешнюю команду в системе, собирает вывод и выполняет некоторые действия на основе того, что было возвращено. Прямо сейчас, вот как я запускаю это (где $cmd-строка с настройкой команды):
@output = `$cmd`;
Я хотел бы изменить это так, если команда зависает и не возвращает значение через столько времени, то я убиваю команду. Как я буду выполнять это асинхронно?
3 ответов
Если вам действительно нужно просто поставить тайм-аут на данный системный вызов, это гораздо проще, чем асинхронное программирование.
все, что вам нужно, это alarm() внутри блока eval ().
вот пример блока кода, который помещает их в подпрограмму, которую вы можете поместить в свой код. Пример вызывает sleep, поэтому не является захватывающим для вывода, но показывает вам функциональность тайм-аута, которая вас интересовала. Выход запуска:
/bin/sleep 2 сбой: тайм-аут при ./ линия тайм-аута 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;
}
есть много способов сделать это:
- вы можете сделать это с помощью вилки (вилка perldoc-f)
- или использование потоков (потоки perldoc). Оба эти передачи возвращается обратно в основную программу сложно.
- на системах, которые поддерживают его, вы можете установить сигнал тревоги (perldoc-F alarm), а затем очистить в обработчике сигнала.
- вы можете использовать цикл событий, как POE или Coro.
- вместо backticks, вы можете использовать open () или соответственно open2 или open3 (см. IPC::Open2, IPC:: Open3) для запуска программы при получении ее STDOUT/STDERR через дескриптор файла. Выполните неблокирующие операции чтения на нем. (perldoc-F выберите и, вероятно, google "perl nonblocking read")
- как более мощный вариант openX (), проверьте IPC::Run/IPC::Cmd.
- вероятно, тонны, о которых я не могу думать посреди ночи.
Если ваша внешняя программа не принимает никаких входных данных, найдите следующие слова в perlipc
manpage:
вот безопасный щуп или труба открыта для чтения:
используйте пример кода и охраняйте его с помощью будильника (который также объясняется в perlipc
).