如何判断 IPC::Run 作业何时完成
Posted
技术标签:
【中文标题】如何判断 IPC::Run 作业何时完成【英文标题】:How to tell when an IPC::Run job has finished 【发布时间】:2016-11-17 06:43:47 【问题描述】:是否有一种简单、可靠的方法来判断 IPC::Run
任务何时完成,即任何子进程已退出?
文档对此保持沉默。
似乎在pumpable
上循环是可行的,尽管它并没有真正清楚地记录为正确的做事方式:
use strict;
use warnings;
use IPC::Run;
use 5.12.0;
my $handle = IPC::Run::start(['sleep', '10']);
while ($handle->pumpable)
sleep(0.5);
# do other stuff in the event loop
# so we don't want to block on finish
$handle->finish;
print("exited with '" . $handle->result . "'");
还有更好的选择吗? finish
阻塞,但是在等待 proc 完成时,您无法在事件循环中执行其他工作。
我很惊讶没有一个简单的
$handle->running
或
$handle->finished
我是否遗漏了一些明显的东西?
同样,似乎没有记录的方式来获取孩子的 pid。
【问题讨论】:
$handle->finish
块,如 wait
。如果你想在等待之前检查,调用result
before child completed 显然会抛出一个异常,所以你可以通过检查异常来使用它——eval $res = $handle->result or print "Still running\n";
。这是一个杂物(应该检查$@
而不是or
-it),但是这样可以吗? result
还有许多其他版本。还有一个signal
,我试图发送一个0
,但什么也没回。文档中似乎暗示不能直接使用 pid。
呃。是的,可以尝试调用result
并捕获异常。丑陋的:(。我应该明确表示我正在寻找一种非阻塞方式,否则我只会使用IPC::Run::run
。谢谢。
对,我确实明白了,但提到阻止以防万一。丑陋,但我现在看不到更清洁的方式。 (这个模块我用的不多。我会多看看,因为我一直想更好地检查它。)
它非常有用,强烈推荐。这是我唯一的问题,以及它明显决定隐藏子进程的 pid。
因此,击败封装不是一个好方法,但是:当您执行Dumper($handle)
时,您将看到对象数据。 (需要use Data::Dumper;
。)由此,我们可以得到$handle->KIDS[0]PID
的pid。那是给第一个孩子的。这个和result
的异常技巧可以包裹在 subs 中,以减轻一点痛苦。
【参考方案1】:
我也找不到干净的方法,只能找到其他方法。
可以通过result
相关方法获取孩子是否在跑步的信息,也可以通过pumpable
获取(问题中已经用到了)。
result
方法“如果传递了超出范围的子编号,则抛出异常”。如果我们查询没有孩子退出的时间,就会发生这种情况。所以,只有一个子进程
sub only_kid_finished eval $_[0]->result ; return $@ ? 0 : 1
更好的是,results
方法返回子退出值列表,同时它还“如果线束未处于完成状态,则抛出异常”。所以它可以以同样的方式使用,但对于更多的孩子,它也可以用来跟踪有多少退出/离开。
正如问题中所使用的,pumpable
还可以告知是否有任何进程正在运行
sub any_kids_left return $_[0]->pumpable
它与 I/O 通道或进程有关,但如果有任何东西正在运行,它必须返回 true,否则返回 false。
儿童 PID 的问题对我来说有点令人烦恼,因为这是人们可能需要知道的信息。虽然它就在对象中,$handle->KIDS[0]PID
(对于第一个孩子),但我不知道如何以合理的方式检索它。我认为这种基本的结构无法改变,所以它会诱使我实际使用它,并进行检查。那么我也会满足于我可能得到的一切,这是应得的。
一旦检索到 PID,就可以使用kill 0, $pid
检查进程。请注意,这将返回 true (1
),直到进程被收割(即使它退出但它是僵尸)。
【讨论】:
【参考方案2】:这是获取子 PID 的解决方法。然后你可以等待孩子或设置一个 SIGCHLD 处理程序。例如:
use feature qw(say);
use strict;
use warnings;
use IPC::Run qw( start );
use Proc::ProcessTable;
my $h = start ['sleep', '5'];
my $pt = Proc::ProcessTable->new();
my $kid;
for my $p (@ $pt->table )
if ( $p->ppid == $$ )
if ( $p->cmndline =~ m/bin/sleep )
$kid = $p->pid;
if ( defined $kid )
say "Waiting for child with PID '$kid' to finish..";
waitpid $kid, 0;
say "Done.";
else
die "Could not find PID of child process\n";
【讨论】:
以上是关于如何判断 IPC::Run 作业何时完成的主要内容,如果未能解决你的问题,请参考以下文章