同时在perl脚本中运行多个作业

时间:2019-01-27 14:30:51

标签: perl for-loop parallel-processing

我必须运行视频编码程序,其中我具有不同的量化参数QP。 QP从0到51。在我的perl脚本中,我遍历此参数并执行命令行。命令行如下:

  

TAppEncoder encoder_intra_main_rext.cfg -i BSEQ.RAW -b BSEQ_1.bin -o / dev / null -qp 1 -wdt 7811 -hgt 7911 -fr 1 -fs 0 -f 2 -InputBitDepth = 16 -OutputBitDepth = 16 --InternalBitDepth = 16 --InputChromaFormat = 400 --ConformanceMode = 1 --SEIDecodedPictureHash >> BSEQ_1.txt

在每次迭代中,我仅更改qp。现在,在我的Perl脚本中,当我执行上面的代码行时,它等待完成,然后继续进行循环中的下一个迭代(例如qp=2)。

顶级shell脚本也调用了perl脚本:

test.sh ---> test.pl ---> command1 with qp=1
                     ---> command2 with qp=2
                     ---> command3 with qp=3
                     ---> command4 with qp=4
                     ---> until the end of the for loop

我想知道如何并行运行两个(或多个)进程。例如,运行qp=1并在qp=2之后立即运行,而不必等待qp=1完成。并且比这两个中的一个完成时(无论qp = 1或qp = 2先完成)运行qp = 3,依此类推。

因此,基本上,我不想并行运行perl脚本,不需要perl脚本的多个实例。我需要脚本(这是循环的一部分)中的命令并行运行。但是,如果还有其他方式可以做到这一点,请告诉我。

代码的一部分在下面,现在它一次运行一个qp。我想一直并行运行2个,一次完成就转到下一个,所以2个进程一直都在运行。

我正在Linux Mint上运行脚本。我在一台计算机上运行它(我没有群集)。想法是将其调整为两个核心。

任何想法如何做到这一点,或者至少从哪里开始? 谢谢。

    $QP_end = $Configuration->{nb_QPs}-1;
    foreach $QP_index (0 .. $QP_end)
    {
      $QP = $Configuration->{QP_list}[$QP_index];
      print($QP," ");
      set_command_line(); # HERE I CHANGE THE QP TO SET NEW COMMAND LINE, AND THEN EXECUTE THE NEW COMMAND
      @RunCommand = ($command_line);
      `@RunCommand`;
    }

2 个答案:

答案 0 :(得分:0)

多年来我一直在使用这样的代码

#!/usr/bin/env perl

use strict;
use warnings 'FATAL' => 'all';
use Cwd 'getcwd';
use feature 'say';
my $TOP_DIRECTORY = getcwd();
use autodie qw(:all);

sub execute {
    my $command = shift;
    print "Executing Command: $command\n";
    if (system($command) != 0) {
        my $fail_filename = "$TOP_DIRECTORY/$0.fail";
        open my $fh, '>', $fail_filename;
        print $fh "$command failed.\n";
        close $fh;
        print "$command failed.\n";
        die;
    }
}

use Parallel::ForkManager;
sub run_parallel {
    my $command_array_reference = shift;
    unless ((ref $command_array_reference) =~ m/ARRAY/) {
        say "run_parallel requires an array reference as input.";
        die;
    }
    my $manager = new Parallel::ForkManager(2);
    foreach my $command (@{ $command_array_reference }) {
        $manager->start and next;
        execute( $command );
        $manager->finish;
    }
    $manager->wait_all_children;#necessary after all lists
}

使用一系列命令run_parallel

执行上述子例程@cmd

您可以从CPAN安装Parallel::ForkManager,例如sudo cpanm Parallel::ForkManager或许多其他方式。

答案 1 :(得分:0)

基于fork()的幼稚方法又如何呢?

# --- Prepare job queues ---
my @jobs = ( ['cmd01'..'cmd10'], ['cmd11'..'cmd20'] ) ;

# --- If fork returns PID means we're in the parent proc ---
# --- otherwise we're in the child proc ---
worker( fork ? $jobs[0] : $jobs[1] ) ;

# --- Worker --- 
sub worker {
    # --- Do jobs ---
    foreach my $cmd ( @{ $_[0] } ){
        # --- Do system command or die if RC > 0 ---
        die $! if system($cmd) ;
    }
}

主要概念是将您的作业队列分成多个块,然后分叉以使并行度为2(或您想要的任何值)的进程,然后每个进程将处理其作业队列。

这是一个工作正常的示例,并行度为2。如果需要更多并行处理,则必须根据所需的并行性和fork()进行parallelism - 1次来实现作业队列的划分。

由于每个分叉的进程都在其自己的地址空间中运行,因此它们彼此之间是不可知的。这意味着,根据您的需要,您可能必须实施IPC机制来控制执行流和依赖关系,但是对于您而言,我认为这是不必要的。

相关问题