我试图在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命令?
您可能希望使用Proc::Async,它在线程中异步运行外部命令,而不需要代码的单独实例来执行此操作。
由于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会更有意义。