如何判断 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 作业何时完成的主要内容,如果未能解决你的问题,请参考以下文章

RabbitMQ 如何将作业拆分为任务并处理结果

如何停止由“无论何时” gem 创建的 cron 作业

如何判断表达式是在编译时还是运行时评估的?

如何在 Firebase 作业调度程序中检测网络断开连接?

Spring传智播客第二章的题(带答案解析)

何时使用 - 延迟作业与 RabbitMQ