Проблема не в количестве обещаний, а в количестве подпроцессов.Один из способов ограничить это - просто ограничить количество, которое вы создаете за раз в логике вашей программы.Вместо того, чтобы порождать их все сразу на карте, установите лимит и получите их из @numbers (возможно, используя splice ) и породите эти подпроцессы;создайте -> все обещания, которые ожидают их, и прикрепите -> затем к этому обещанию, чтобы получить ваш следующий кусок чисел и т. д.
Другой вариант - использовать Future :: Utils fmap_concat, который может позаботиться о коде, ограничивающем скорость, если вы предоставите количество максимально ожидаемых фьючерсов.Ваша функция, возвращающая обещание, может применять Mojo :: Promise :: Role :: Futurify для создания цепочки следующего будущего для использования таким образом.
#!/usr/bin/env perl
use Mojolicious::Lite;
use Mojo::File 'path';
use Mojo::IOLoop;
use Mojo::Promise;
use Future::Utils 'fmap_concat';
get '/' => sub {
my $c = shift;
my $count = $c->param('count') // 0;
my @numbers = 1..$count;
if (@numbers) {
my $result_f = fmap_concat {
my $number = shift;
my $p = Mojo::Promise->new;
Mojo::IOLoop->subprocess(sub {
sleep 2;
return $number+1;
}, sub {
my ($subprocess, $err, @result) = @_;
return $p->reject($err) if $err;
$p->resolve(@result);
});
return $p->with_roles('Mojo::Promise::Role::Futurify')->futurify;
} foreach => \@numbers, concurrent => 20;
$result_f->on_done(sub {
my @values = @_;
foreach my $response (@values) {
$c->app->log->info($response);
}
})->on_fail(sub {
my $error = shift;
$c->app->log->fatal($error);
})->retain;
$c->stash(done => 1);
}
$c->render(text => "Processing $count numbers\n");
};
app->start;
Что касается метода ожидания, этотничего не делает, когда цикл событий уже запущен, что в обработчике ответов webapp будет, если вы запустили приложение в Mojolicious-демоне (в отличие от сервера PSGI или CGI, который не поддерживает асинхронные ответы).Вызовы -> stash и -> render вне колбэков будут выполняться сразу после настройки подпроцессов.Затем обработчик ответа завершится, и цикл обработки событий снова получит управление, которое вызовет соответствующие -> затем обратные вызовы после разрешения обещаний.Рендер не должен ждать чего-либо кроме настройки подпроцессов;так как вы сказали, что могут быть сотни, это может быть замедлением, которое вы испытываете.Убедитесь, что вы используете Mojolicious 7.86 или новее, так как Subprocess был изменен, так что разветвление не произойдет до следующего тика цикла обработки событий (после того, как обработчик вашего ответа завершится).
Я также отмечу, что подпроцессы не нужныдействительно предназначен для этого;они предназначены для выполнения медленного кода, который все еще возвращает возможный результат браузеру в ответе (и Mojolicious :: Plugin :: Subprocess хорош для этого варианта использования).Одна проблема, которую я вижу, состоит в том, что если вы перезапустите приложение, все еще ожидающие подпроцессы будут просто игнорироваться.Для заданий, которые вы хотите отключить и забыть, вы можете рассмотреть очередь заданий, например Minion , которая прекрасно интегрируется в приложения Mojolicious и запускается через отдельный рабочий процесс.