【发布时间】:2010-12-17 15:57:09
【问题描述】:
我目前有一个 Perl 脚本,它在系统上运行外部命令、收集输出并根据返回的内容执行一些操作。现在,这是我运行它的方式(其中 $cmd 是带有命令设置的字符串):
@output = `$cmd`;
我想改变这个,所以如果命令挂起并且在很长时间后没有返回值,那么我会终止该命令。我将如何异步运行它?
【问题讨论】:
标签: perl
我目前有一个 Perl 脚本,它在系统上运行外部命令、收集输出并根据返回的内容执行一些操作。现在,这是我运行它的方式(其中 $cmd 是带有命令设置的字符串):
@output = `$cmd`;
我想改变这个,所以如果命令挂起并且在很长时间后没有返回值,那么我会终止该命令。我将如何异步运行它?
【问题讨论】:
标签: perl
有很多方法可以做到这一点:
【讨论】:
select,它仅适用于套接字以及与控制台窗口的潜在奇怪交互,wperl(以非控制台窗口方式运行 perl,但对 STDIO 和子进程)。从好的方面来说,你可以做一个system(-1, 'foo')。此外,某些启动进程的方法在运行 64 个子进程后会失败。输入法,Win32::Process::Create() 是在 bgrnd 中运行程序的最安全方式。
如果你真的只需要在给定的系统调用上设置一个超时时间,那是一个比异步编程简单得多的问题。
你所需要的只是一个 eval() 块内的 alarm()。
这是一个示例代码块,它将这些代码块放入您可以放入代码中的子例程中。该示例调用 sleep ,因此输出并不令人兴奋,但确实向您展示了您感兴趣的超时功能。 运行它的输出是:
/bin/sleep 2 失败:超时 ./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;
}
【讨论】:
如果您的外部程序不接受任何输入,请在 perlipc 手册页中查找以下字词:
这是一个安全的反引号或管道打开以供阅读:
使用示例代码并用警报保护它(perlipc 中也有解释)。
【讨论】: