Last active
August 17, 2016 21:27
-
-
Save klopp/40dfa4b4f4d81218a8bff63d4b86db53 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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