【问题标题】:Run multiple jobs within perl script at the same time同时在 perl 脚本中运行多个作业
【发布时间】:2019-01-28 03:12:13
【问题描述】:

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

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`;
    }

【问题讨论】:

  • 你为什么要使用 Perl?该任务在 shell 脚本中将是微不足道的。此外,您是否要求按特定顺序收集输出,或者并行任务是否可以按照它们碰巧完成的顺序写入输出文件?
  • 顺序无关紧要。我使用 perl 是因为我继承了以前从事此工作的人的代码。脚本本身有大约 1300 行(我们必须在其中设置和检查多种配置),并且为我(这里是新手)在 shell 中重写它会花费很多时间。
  • @tripleee 但是我使用顶级 bash 脚本 ( test.sh ) 运行 perl 脚本 从 test.sh 我运行 perl 脚本(仅一次,没有 for 循环)运行我之前提到的命令。这对你来说意味着什么吗?可以在 shell 脚本中并行化吗?

标签: perl for-loop parallel-processing


【解决方案1】:

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

#!/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
}

用你的一系列命令@cmd执行上述子程序run_parallel

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

【讨论】:

  • 谢谢。我已经探索了 Parallel::ForkManager 并找到了解决方案。
【解决方案2】:

基于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 机制来控制执行流程和依赖关系,但在您的情况下,我认为没有必要。

【讨论】:

    猜你喜欢
    • 2013-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-05
    • 2011-07-14
    • 2017-05-08
    • 2023-04-07
    • 2021-06-06
    相关资源
    最近更新 更多