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
相关产品推荐
相关产品推荐

