Perl Mojolicious中使用Promise->all_settled时如何限制并发?
在Mojolicious中结合Promise->all_settled实现并发限制的方法
Mojolicious的Mojo::Promise->all_settled本身没有内置并发限制参数,但可以通过Mojo::Promise->map的concurrency选项来实现——先控制任务的并发执行数量,再收集所有任务的结果(无论成功失败),效果等价于带并发限制的all_settled。
核心思路
直接生成50个isOdd_p Promise会同时启动50个子进程,并发过高。我们可以用Promise->map限制同时运行的Promise数量为10,同时为每个Promise添加then/catch包装,把成功/失败的结果转换成统一格式的对象(和all_settled返回的结果结构一致),这样就能既控制并发,又收集所有状态。
修改后的完整代码
use Mojolicious::Lite -signatures, -async_await; helper isOdd_p => sub($self, $number) { return Mojo::Promise->new(sub($resolve, $reject ) { Mojo::IOLoop->subprocess( sub { sleep 1; $number % 2; }, sub ($subprocess, $err, @res ) { $reject->( $err ) if $err; $reject->( @res ) if @res && $res[0]==0; # 偶数时reject $resolve->( @res ); }) }); }; any '/' => async sub ($c) { $c->render_later(); # 用Promise->map控制并发,并包装结果为all_settled格式 my @results = await Mojo::Promise->map( {concurrency => 10}, sub { my $num = shift; return $c->isOdd_p($num) ->then(sub { return {status => 'fulfilled', value => shift} }) ->catch(sub { return {status => 'rejected', reason => shift} }); }, 0..50 ); # 注:all_settled永远不会reject,所以原代码里的$@分支永远不会执行 $c->render(json => [ @results ] ); }; app->start;
关键说明
- 并发控制:
{concurrency => 10}选项让Promise->map同时最多运行10个Promise,避免一次性启动过多子进程。 - 结果格式对齐
all_settled:通过then和catch把每个Promise的结果包装成包含status和对应值/原因的对象,和all_settled返回的结果结构完全一致。 - 原代码疑问解答:
Mojo::Promise->all_settled总是会resolve,不会触发reject,所以原代码里的if (my $err = $@)分支永远不会被执行。
内容的提问来源于stack exchange,提问作者h q
相关产品推荐
相关产品推荐

