Команда времени ожидания Perl в Windows и Linux - PullRequest
0 голосов
/ 14 декабря 2018

Я пишу Perl-скрипт, который должен работать в Windows и Linux, который будет запускать процесс, тайм-аут, если он занимает слишком много времени, вернуть код завершения, если он не истек, и вернуть stdout, предполагая, что код выхода равен нулю.и это не истекло время ожидания.Мне не нужны STDIN или STDERR.Я пытался использовать IPC::run, но не смог заставить его работать.

Самое близкое, что я получил, это IPC::Open3 и waitpid($pid, WNOHANG).Но я наткнулся на препятствие.Я вижу разные результаты на Windows и Linux.В приведенном ниже коде я даю open3 команду, которая не будет выполнена (ping не имеет аргументов -z).В Linux этот код немедленно возвращает отрицательный код выхода.На окнах команда истекает.Запуск ping google.com -z в командной строке Windows немедленно возвращает сообщение о том, что такого аргумента нет.Почему `` waitpid` возвращает ноль? *

use strict;
use warnings;
use POSIX ":sys_wait_h";
use IPC::Open3;

my $inFH;
my $outFH;
my @cmd = ("ping", "google.com", "-z");
my $pid = open3( $inFH, $outFH, 0, @cmd);
my $counter=0;
my $waitret;
my $exitcode;
do{
    $counter++;
    $waitret = waitpid($pid,WNOHANG);   
    $exitcode = $?;
}while( !$waitret and ($counter < 4_000_000));

if ($counter >= 4_000_000) {
    print "Command timed out\n";
    kill(9, $pid);
} else {
    print "Exit Code: $exitcode\n";
}

Другие решения приветствуются.Единственная причина, по которой я использую waitpid с nohang, - это завершение процесса, если он занимает слишком много времени.У меня нет никакой другой обработки, которую я должен сделать тем временем.Я использую Windows 10 клубника Perl 5.28 портативных на Windows.На моем компьютере с Debian установлен Perl 5.24.

1 Ответ

0 голосов
/ 14 декабря 2018

IPC :: Run поддерживает различные таймауты и таймеры , которые также должны работать на Win32.

Basic:

use warnings;
use strict;
use feature 'say';

use IPC::Run qw(run timeout);

my $out;

eval {
    run [ qw(sleep 20) ], \undef, \$out, timeout(2) or die "Can't run: $?"
};  
if ($@) { 
    die $@ if $@ !~ /^IPC::Run: timeout/;
    say "Eval: $@";
}

timeout выдает исключение, таким образом eval.Существуют и другие таймеры с более тонким и управляемым поведением.Пожалуйста, смотрите документацию.

Исключение перебрасывается, если обнаруженное не вызвано таймером IPC::Run - судя по тому, что версия модуля в моей системе печатает в сообщении, строка начинаетсяс IPC :: Run: время ожидания .Пожалуйста, проверьте, что это в вашей системе.

Хотя некоторые вещи не работают в Windows, таймеры должны, я думаю.Я не могу проверить прямо сейчас.


Сообщается, что, хотя вышеприведенное работает, с более значимой командой на месте SIGBREAK (21) выдается по истечении времени ожидания, и после обработки процесс остаетсявокруг.

В этом случае завершите его вручную в обработчике

use warnings;
use strict;
use feature 'say';
use IPC::Run qw(run harness timeout);

my $out;
my @cmd = qw(sleep 20);

my $h = harness \@cmd, \undef, \$out, timeout(2);

HANDLE_RUN: {
    local $SIG{BREAK} = sub {
        say "Got $_[0]. Terminate IPC::Run's process";
        $h->kill_kill;
    };  

    eval { run $h };  
    if ($@) { 
        die $@ if $@ !~ /^IPC::Run: timeout/;
        say "Eval: $@";
    }
};

Для того, чтобы можно было использовать kill_kill модуля, здесь я сначала создаю жгут, который затем становится доступным, когдаобработчик установлен, и на котором kill_kill может вызываться при его запуске.

Другим способом было бы найти идентификатор процесса (с помощью Win32 :: Process :: Info или Win32 :: Process :: List ) и завершите его с помощью kill или Win32 :: Process или TASKKILL.См. этот пост (вторая половина).

Блок добавляется только к (значимо) local -размеру обработчика сигнала.В реальном коде все это, вероятно, каким-то образом ограничено, поэтому дополнительный блок может не понадобиться.

Обратите внимание, что в Windows нет сигналов POSIX и что Perl эмулирует только несколько очень простых сигналов UNIX вместе сДля Windows SIGBREAK.

...