Perl6:无法调用此对象(REPR:P6opaque; Parallel :: ForkManager)

问题描述 投票:3回答:2

我试图在Perl6中并行运行一系列shell命令,使用Perl5的Parallel::ForkManager这是工作Perl5代码的几乎完全翻译。

CONTROL {
    when CX::Warn {
        note $_;
        exit 1;
    }
}
use fatal;
role KeyRequired {
    method AT-KEY (\key) {
        die "Key {key} not found" unless self.EXISTS-KEY(key);
        nextsame;
    }
}

use Parallel::ForkManager:from<Perl5>;

sub run_parallel (@cmd) {
    my $manager = Parallel::ForkManager(8).new();
    for (@cmd) -> $command  {
        $manager.start and $manager.next;
        my $proc = shell $command, :out, :err;
        if $proc.exitcode != 0 {
            put "$command failed";
            put $proc.out.slurp;
            put $proc.err.slurp;
            die;
        }
        $manager.finish;
    }
    $manager.wait_all_children;#necessary after all lists
}

my @cmd;
my Str $dir = 'A/1';
for dir($dir, test => /\.vcf\.gz$/) -> $vcf {
    @cmd.append: "aws s3 cp $vcf s3://s3dir/$dir/"
}
put @cmd.elems;
run_parallel(@cmd);

基本上,我正在尝试并行化繁琐的shell命令。

然而,这个神秘的错误出现了:

无法在2.aws_cp.p6第39行的块中的2.aws_cp.p6第18行的子run_parallel中调用此对象(REPR:P6opaque; Parallel :: ForkManager)

为什么Perl6会说这个?怎么了?我怎样才能运行这些命令?

也许在Perl6中有一种更原生/惯用的方式来并行运行shell命令?

perl6
2个回答
7
投票

您可能希望使用Proc::Async,它在线程中异步运行外部命令,而不需要代码的单独实例来执行此操作。


5
投票

由于Inline :: Perl5的实现方式,Perl5的Parallel :: ForkManager可能无法在Perl6中工作。

Inline :: Perl5在Perl6中嵌入了Perl5编译器/运行时。

Parallel :: ForkManager期望Perl5自己运行。

如果你曾经让它做除了生成错误之外的其他事情,它可能搞砸了Perl6运行时。主要问题是使用fork。有关为什么fork成为问题的更多信息,请参阅Bart Wiegmans(brrt)撰写的文章:“A future for fork(2)”


Perl6已经具有更易于使用的类似功能。

sub run_parallel (@cmd) {
    my @children = do for (@cmd) -> $command  {
        start {
            my $proc = shell $command, :out, :err;
            if $proc.exitcode != 0 {
                put "$command failed";
                put $proc.out.slurp;
                put $proc.err.slurp;
                die;
            }
        }
    }
    await @children;
}

start是一个前缀,它告诉运行时在不久的将来某个时候开始运行以下代码。它返回一个Promise。 await获取Promises列表并返回其结果列表。

start基本上称Promise.start,类似于:

sub start ( &code ) {
    my $promise = Promise.new;
    my $vow = $promise.vow;

    $*SCHEDULER.cue(
        { $vow.keep(code(|c)) },
        :catch(-> $ex { $vow.break($ex); }) );
    $promise
}

因此它将使用$*SCHEDULER中全局可用的线程池。如果你想单独使用一个。

sub run_parallel (@cmd) {
    my $*SCHEDULER = ThreadPoolScheduler.new(max_threads => 8);

    my @children = do for (@cmd) -> $command  {
        start {
            my $proc = shell $command, :out, :err;
            if $proc.exitcode != 0 {
                put "$command failed";
                put $proc.out.slurp;
                put $proc.err.slurp;
                die;
            }
        }
    }
    await @children;
}

尽管如此,使用Proc :: Async会更有意义。

© www.soinside.com 2019 - 2024. All rights reserved.