Skip to content

Instantly share code, notes, and snippets.

@klopp
Last active August 17, 2016 21:27
Show Gist options
  • Save klopp/40dfa4b4f4d81218a8bff63d4b86db53 to your computer and use it in GitHub Desktop.
Save klopp/40dfa4b4f4d81218a8bff63d4b86db53 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
# -----------------------------------------------------------------------------
use Modern::Perl;
use AnyEvent;
use AnyEvent::HTTP;
use Const::Fast;
# -----------------------------------------------------------------------------
# Задача: распараллелить N действий так, чтобы в T секунд совершалось не больше
# M действий.
#
# Применим следующий подход: будем создавать пачки по M действий и после
# завершения последнего из них проверять сколько времени заняла вся пачка.
# Меньше T секунд - спим остаток времени. Действия эмулируем запросами к URL.
#
# В качестве таймера и сна используются средства AnyEvent, просто чтобы не
# плодить сущностей. Хотя было бы короче воспользоваться Time::HiRes.
#
# NB! У этого метода есть фатальный недостаток. Если хотя бы один запрос
# из пачки зависнет, то встанет вся очередь.
#
# -----------------------------------------------------------------------------
const my $MAX_WORKERS => 10; # количество одновременных запросов (M)
const my $INTERVAL => 1.0; # интервал (T)
const my $DEBUG => 1;
const my $URLTEMPLATE => 'http://127.0.0.1/';
my @data = ( 1 .. ( $MAX_WORKERS * 10 ) );
# -----------------------------------------------------------------------------
while (@data) {
my $tstart = AnyEvent->time();
my $cv = AnyEvent->condvar();
# формируем $MAX_WORKERS одновременных запросов:
for ( 0 .. $MAX_WORKERS ) {
my $foo = shift @data;
if ( defined $foo ) {
$cv->begin();
my $url = "$URLTEMPLATE-$foo-";
http_get(
$url,
sub {
my ( $data, $headers ) = @_;
say "$url -> " . $headers->{Status} if $DEBUG;
$cv->end();
}
);
}
}
$cv->recv();
last unless @data;
my $sleeping = $INTERVAL - ( AnyEvent->time() - $tstart );
# слишком быстро - поспим:
if ( $sleeping > 0 ) {
say "sleeping for $sleeping seconds..." if $DEBUG;
my $sleep = AnyEvent->condvar();
my $timer = AnyEvent->timer( after => $sleeping, cb => $sleep );
$sleep->recv();
}
else {
say 'no sleeping needed' if $DEBUG;
}
}
say 'Done.';
# -----------------------------------------------------------------------------
# That's All, Folks!
# -----------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment