我试图使用Perl5在Perl6中并行运行一系列Shell命令。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);
Run Code Online (Sandbox Code Playgroud)
基本上,我正在尝试并行化乏味的shell命令。
但是,出现了这个神秘的错误:
无法在2.aws_cp.p6第39行的块中的sub.run_parallel中调用此对象(REPR:P6opaque; Parallel :: ForkManager)
为什么Perl6这样说?怎么了?如何使这些命令运行?
也许有一种更本机/惯用的方式在Perl6中并行运行Shell命令?
Perl5's Parallel::ForkManager probably won't work in Perl6 because of how Inline::Perl5 is implemented.
Inline::Perl5 embeds the Perl5 compiler/runtime inside of Perl6.
Parallel::ForkManager expects that Perl5 was run by itself.
If you ever did get it to do something other than generate an error it would probably screw up the Perl6 runtime. The main problem is the use of fork. For more information about why fork is a a problem see the article Bart Wiegmans (brrt) wrote about it: “A future for fork(2)”
Perl6 already has a similar feature that is easier to use.
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;
}
Run Code Online (Sandbox Code Playgroud)
start is a prefix that tells the runtime to start running the following code sometime in the near future. It returns a Promise.
await takes a list of Promises and returns a list of their results.
start basically calls Promise.start which is similar to:
sub start ( &code ) {
my $promise = Promise.new;
my $vow = $promise.vow;
$*SCHEDULER.cue(
{ $vow.keep(code(|c)) },
:catch(-> $ex { $vow.break($ex); }) );
$promise
}
Run Code Online (Sandbox Code Playgroud)
So it will use the globally available thread pool in $*SCHEDULER. If you want to use a separate one you could.
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;
}
Run Code Online (Sandbox Code Playgroud)
It would make more sense to use Proc::Async for this though.