Perl:监视后台进程的输出而不等待它完成

时间:2012-08-23 18:57:55

标签: perl process background monitor

我正在尝试用Perl编写一个经理来自动化我实验室一直使用的生物信息学管道。 (REPET管道,适用于任何感兴趣的人。)管道有八个步骤,其中几个分为子步骤,可以并行运行。最值得注意的是,步骤3分为三个部分,步骤4分为三个相应的部分。步骤3的每个部分可以独立运行,并且步骤4中的相应部分可以在其步骤3伴随完成后立即开始。我希望我的经理能够在三个并行线程中启动第3步,并且对于每个线程,只要第3步完成,就转到第4步。我能想到的最佳方法是监控每个流程的输出。每个步骤的输出如下所示:

START TEdenovo.py (2012-08-23 11:20:10)
version 2.0
project name = dm3_chr2L
project directory = /home/<etc>
beginning of step 1
submitting job(s) with groupid 'dm3_chr2L_TEdenovo_prepareBatches' (2012-08-23 11:20:10)
waiting for 1 job(s) with groupid 'dm3_chr2L_TEdenovo_prepareBatches' (2012-08-23 11:20:10)
execution time per job: n=1 mean=2.995 var=0.000 sd=0.000 min=2.995 med=2.995 max=2.995
step 1 finished successfully
version 2.0
END TEdenovo.py (2012-08-23 11:20:25)

这是步骤1的输出,但是在步骤3中,当“步骤3成功完成”出现在输出中时,可以安全地继续执行步骤4.该问题已成功将其中三个进程的输出列表为他们立刻跑了。从本质上讲,这是我想要的行为(伪代码):

my $log31 = `TEdenovo.py [options] &`;
my $log32 = `TEdenovo.py [options] &`;
my $log33 = `TEdenovo.py [options] &`;

while(1) {
    #start step 41 if $log31 =~ /step 3 finished successfully/;
    #start step 42 if $log32 =~ /step 3 finished successfully/;
    #start step 43 if $log33 =~ /step 3 finished successfully/;
    #monitor logs 41, 42, 43 similarly
    last if #all logs read "finished successfully"
    sleep(5);
}

#move on to step 5

问题在于,使用反引号唤起进程会导致perl等待该进程完成继续进行;正如我发现的那样,它与system()不同,在那里你可以使用&amp ;;然后立即进行。据我所知,没有一种好方法可以使用system()来获得我正在寻找的效果。我想我能做到这一点:

system("TEdenovo.py [options] & > log31.txt");

然后定期轮询log31.txt以查看“已成功完成”是否已出现,但这看起来似乎非常混乱。

我也试过用文件句柄打开过程:

open(my $step3, "TEdenovo.py [options] |");
my @log3;

while(1)
{
    push(@log3, <$step3>);
    last if grep("step 3 finished successfully", @log3);
    sleep(5);
}

...但是,Perl再次等待,直到进程完成才能继续(在这种情况下,在push())。我用$ |尝试了上面的内容设置和取消设置。

所以,我的问题的实质是:有没有办法在perl中捕获正在运行的后台进程的标准输出?

2 个答案:

答案 0 :(得分:1)

也许你可以试试

open(my $step3, "TEdenovo.py [options] |");

while(<$step3>)
{
    last if /step 3 finished successfully/;
}

而不是while(1)?

答案 1 :(得分:0)

使用open和读取pipehandle的方法是 一种正确的方法。如果Nahuel在标量语境中从句柄中读取的建议没有帮助,那么你仍然可能会遭受缓冲。

$|改变了Perl输出的缓冲行为,但没有改变从Perl调用的任何外部程序的行为。您必须使用不缓冲其输出的外部程序。在这种情况下,我相信通过将-u选项传递给python:

可以实现这一点
open(my $step3, "|-", "python -u TEdenovo.py [more options]");