Perl6: невозможно вызвать этот объект (REPR: P6opaque; Parallel :: ForkManager) - PullRequest
3 голосов
/ 21 марта 2019

Я пытаюсь запустить серию команд оболочки параллельно в Perl6, используя 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);

По сути, я пытаюсьраспараллелить утомительные команды оболочки.

Однако возникает таинственная ошибка:

Невозможно вызвать этот объект (REPR: P6opaque; Parallel :: ForkManager) в sub run_parallel в строке 2.aws_cp.p6 18 в блоке 18 в блокев 2.aws_cp.p6 строка 39

Почему Perl6 говорит это?что случилось?как я могу заставить эти команды выполняться?

Возможно, есть более родной / идиоматический способ параллельного запуска команд оболочки в Perl6?

Ответы [ 2 ]

7 голосов
/ 21 марта 2019

Возможно, вы захотите взглянуть на использование Proc :: Async , которое асинхронно выполняет внешние команды в потоках, не разветвляя отдельные экземпляры кода для этого.

5 голосов
/ 22 марта 2019

Perl5 Parallel :: ForkManager , вероятно, не будет работать в Perl6 из-за того, как реализован Inline :: Perl5 .

Inline :: Perl5 встраивает компилятор / среду выполнения Perl5 в Perl6.

Parallel :: ForkManager ожидает, что Perl5 был запущен сам по себе.

Если вы когда-нибудь его получилисделайте что-нибудь кроме генерирования ошибки, это вероятно испортило бы время выполнения Perl6.Основной проблемой является использование fork.Для получения дополнительной информации о том, почему fork является проблемой, см. Статью, которую Барт Вигманс (brrt) написал об этом: «Будущее для 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, принимает список Promise s и возвращает список их результатов.

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 .

...