You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mojo::IOLoop::Subprocess参数传递与并行等待结果问题求助

Mojolicious子进程并行与参数传递问题及闭包变量疑问

我正在研究Mojolicious框架中子进程的工作机制,编写了如下测试代码:

use Mojo::Base -strict, -signatures;
use Mojo::IOLoop::Subprocess;

show "BEFORE";
    
for(0..5){
    say "(START) This is $_ loop";
    
    my $subprocess = Mojo::IOLoop::Subprocess->new;
    
    $subprocess->run(
        map {
            sub {
                my $sp = shift; # $subprocess
                my $i = shift; # looking to get my param here
                say "Hello, from $i!";
                sleep 5;
                say "Good bye, from $i!";
                return 'Done', $i;
            },
            sub ($subprocess, $err, @results) {
                say "Subprocess error: $err" and return if $err;
                say "$results[0] SP: $results[1]!";
            }
         } $_ # assuming to send the $_ from the for() loop
    );
    
    $subprocess->ioloop->start unless $subprocess->ioloop->is_running;
    say "(END) This is $_ loop";
}
    
show "AFTER";

运行后出现两个问题:

  • 无法实现主进程等待所有子进程并行执行完毕后再继续,"AFTER"字符串提前输出;
  • 无法将for循环中的参数传递到子进程中,$i始终未初始化,尝试使用map()也未成功。

我曾尝试Future async/await、Mojo async/await、Promise等异步方案,但因子进程内包含sleep()这类阻塞代码而无法达到并行效果。子进程确实使用独立进程(通过$$可验证),但上述问题仍未解决。


UPDATE 1:解决等待问题,参数传递仍未解决

通过提示,使用run_p结合Promise的all_settled解决了等待子进程完成的问题,但参数传递仍未解决:

use Mojo::Base -strict, -signatures, -async_await;
use Mojo::IOLoop::Subprocess;   
  
async sub testMethod{          
    show "BEFORE";
        
    my @promises;
        
    for(0..5){
        say "(START) This is $_ loop";
            
        my $subprocess = Mojo::IOLoop::Subprocess->new;
        
        push @promises, $subprocess->run_p(
            sub {
                my $i = shift || 1;
                #my $promise = Mojo::Promise->new;
                say "Hello, from $i and $$!";
                sleep 5;
                say "Good bye, from $i and $$!";
                #$promise->resolve("Done for $i");
                #return $promise;
                return "Done for $i";
            }
        )->then(sub ($_result) {
            show $_result;
            return $_result;
        })->catch(sub  {
            my $err = shift;
            say "Subprocess error: $err";
        });
        $subprocess->ioloop->start unless $subprocess->ioloop->is_running;
        say "(END) This is $_ loop";
    }
        
    my @results = await Mojo::Promise->all_settled(@promises); 
    show @results;
    show "AFTER";
}

UPDATE 2:匿名子传参导致串行执行并报错

尝试通过匿名子直接传参,但导致进程变为串行执行且报错:

sub {
    my $i = shift || 1;
    my $promise = Mojo::Promise->new;
    say "Hello, from $i and $$!";
    sleep 2;
    say "Good bye, from $i and $$!";
    
    $promise->resolve("Done for $i");
    return $promise;
    #return "Done for $i";
}->($_)

对应的报错输出:

======(  "BEFORE"  )===========[ 'Test.pm', line 189 ]======

    "BEFORE"


(START) This is 0 loop
Hello, from 1 and 15396!
Good bye, from 1 and 15396!
(END) This is 0 loop
(START) This is 1 loop
Hello, from 1 and 15396!
Good bye, from 1 and 15396!
(END) This is 1 loop
(START) This is 2 loop
Hello, from 2 and 15396!
Good bye, from 2 and 15396!
(END) This is 2 loop
(START) This is 3 loop
Hello, from 3 and 15396!
Good bye, from 3 and 15396!
(END) This is 3 loop
(START) This is 4 loop
Hello, from 4 and 15396!
Good bye, from 4 and 15396!
(END) This is 4 loop
(START) This is 5 loop
Hello, from 5 and 15396!
Good bye, from 5 and 15396!
(END) This is 5 loop
Subprocess error: Can't locate object method "Promise=HASH(0xdc13e18)" via package "Mojo" at /home/ubuntu/perl5/perlbrew/perls/perl-5.26.3/lib/site_perl/5.26.3/Mojo/IOLoop/Subprocess.pm line 53.

Subprocess error: Can't locate object method "Promise=HASH(0xdc0f008)" via package "Mojo" at /home/ubuntu/perl5/perlbrew/perls/perl-5.26.3/lib/site_perl/5.26.3/Mojo/IOLoop/Subprocess.pm line 53.

Subprocess error: Can't locate object method "Promise=HASH(0xdc0a6c8)" via package "Mojo" at /home/ubuntu/perl5/perlbrew/perls/perl-5.26.3/lib/site_perl/5.26.3/Mojo/IOLoop/Subprocess.pm line 53.

Subprocess error: Can't locate object method "Promise=HASH(0xdc03968)" via package "Mojo" at /home/ubuntu/perl5/perlbrew/perls/perl-5.26.3/lib/site_perl/5.26.3/Mojo/IOLoop/Subprocess.pm line 53.

Subprocess error: Can't locate object method "Promise=HASH(0xdc134d0)" via package "Mojo" at /home/ubuntu/perl5/perlbrew/perls/perl-5.26.3/lib/site_perl/5.26.3/Mojo/IOLoop/Subprocess.pm line 53.

Subprocess error: Can't locate object method "Promise=HASH(0xdc15988)" via package "Mojo" at /home/ubuntu/perl5/perlbrew/perls/perl-5.26.3/lib/site_perl/5.26.3/Mojo/IOLoop/Subprocess.pm line 53.

======(  @results  )===========[ 'Test.pm', line 224 ]======

    [
      { status => "fulfilled", value => [1] },
      { status => "fulfilled", value => [1] },
      { status => "fulfilled", value => [1] },
      { status => "fulfilled", value => [1] },
      { status => "fulfilled", value => [1] },
      { status => "fulfilled", value => [1] },
    ]


======(  "AFTER"  )============[ 'Test.pm', line 233 ]======

    "AFTER"

UPDATE 3:已解决参数传递问题

通过将循环数据存入数组,改用foreach遍历数组变量的方式成功解决参数传递问题,完整代码如下:

use Mojo::Base -strict, -signatures, -async_await;
use Mojo::IOLoop::Subprocess;
use Mojo::Promise;

async sub testMehod{
    $c->render_later;
    my $start_timer1 = Time::HiRes::gettimeofday();

    show "BEFORE";

    my @promises;
    
    my @looper = (0..5);
    
    foreach my $lp (@looper){
        say "(START) This is $lp loop";
        
        my $subprocess = Mojo::IOLoop::Subprocess->new;
            
        push @promises, $subprocess->run_p(
            sub {
                my $i = $lp || 5;
                my $sp = shift; # $subprocess
                #my $i = shift || 3;
                #my $promise = Mojo::Promise->new;
                
                say "Hello, from $i and $$!";
                sleep 2;
                say "Good bye, from $i and $$!";
                
                #$promise->resolve("Done for $i");
                #return $promise;
                return "Done for $i";
            }
        )->then(sub ($_result) {
            show $_result;
            return $_result;
        })->catch(sub  {
            my $err = shift;
            say "Subprocess error: $err";
        });
        $subprocess->ioloop->start unless $subprocess->ioloop->is_running;
        say "(END) This is $lp loop";
    }

    my @results = await Mojo::Promise->all_settled(@promises); 
    show @results;

    my $stop_timer1 = Time::HiRes::gettimeofday();
    my $total1 = sprintf("%.5f\n", $stop_timer1 - $start_timer1);

    return $c->render(text => "All done. Parallel: within $total1", status => 405);
}

核心疑问

为何for循环内的变量无法在子进程闭包中使用?


内容的提问来源于stack exchange,提问作者Arsenii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 21:26:59