Я несколько раз выполнил некоторые задачи обслуживания на нескольких сценариях Perl. Одно из требований - загрузить пару десятков файлов (HTTP) параллельно. Я просмотрел CPAN для самого простого решения и нашел этот модуль под названием IO::Lambda::HTTP.IO :: Lambda in Perl
К сожалению, у меня нет абсолютно никакого опыта работы с функциональным программированием (и опытом Perl на начальном уровне), поэтому, хотя я вижу, что все примеры работают как задокументированные, я не могу никого изменить в соответствии с моими потребностями.
Например, образец, который поставляется с модулем:
#!/usr/bin/perl
# $Id: parallel.pl,v 1.7 2008/05/06 20:41:33 dk Exp $
#
# This example fetches two pages in parallel, one with http/1.0 another with
# http/1.1 . The idea is to demonstrate three different ways of doing so, by
# using object API, and explicit and implicit loop unrolling
#
use lib qw(./lib);
use HTTP::Request;
use IO::Lambda qw(:lambda);
use IO::Lambda::HTTP qw(http_request);
use LWP::ConnCache;
my $a = HTTP::Request-> new(
GET => "http://www.perl.com/",
);
$a-> protocol('HTTP/1.1');
$a-> headers-> header(Host => $a-> uri-> host);
my @chain = (
$a,
HTTP::Request-> new(GET => "http://www.perl.com/"),
);
sub report
{
my ($result) = @_;
if (ref($result) and ref($result) eq 'HTTP::Response') {
print "good:", length($result-> content), "\n";
} else {
print "bad:$result\n";
}
# print $result-> content;
}
my $style;
#$style = 'object';
#$style = 'explicit';
$style = 'implicit';
# $IO::Lambda::DEBUG++; # uncomment this to see that it indeed goes parallel
if ($style eq 'object') {
## object API, all references and bindings are explicit
sub handle {
shift;
report(@_);
}
my $master = IO::Lambda-> new;
for (@chain) {
my $lambda = IO::Lambda::HTTP-> new($_);
$master-> watch_lambda($lambda, \&handle);
}
run IO::Lambda;
} elsif ($style eq 'explicit') {
#
# Functional API, based on context() calls. context is
# $obj and whatever arguments the current call needs, a RPN of sorts.
# The context though is not stack in this analogy, because it stays
# as is in the callback
#
# Explicit loop unrolling - we know that we have exactly 2 steps
# It's not practical in this case, but it is when a (network) protocol
# relies on precise series of reads and writes
this lambda {
context $chain[0];
http_request \&report;
context $chain[1];
http_request \&report;
};
this-> wait;
} else {
# implicit loop - we don't know how many states we need
#
# also, use 'tail'
this lambda {
context map { IO::Lambda::HTTP-> new($_, async_dns => 1) } @chain;
tails { report $_ for @_ };
};
this-> wait;
}
работает как рекламируется, но я не могу за жизнь мне понять, как изменить либо «объект» или «неявное» примеры ограничиваться экземплярами N параллельных как следующий из IO :: конспект Lambda в:
# http://search.cpan.org/~karasik/IO-Lambda/lib/IO/Lambda.pm
# crawl for all urls in parallel, but keep 10 parallel connections max
print par(10)-> wait(map { http($_) } @hosts);
Может кто-то показать мне пример того, что код лямбда будет выглядеть с учетом приведенных выше ограничений (например, ограничение на N экземпляров) ?
Также, как лучше всего начать изучение функционального программирования? Мне кажется совершенно чуждым.
Согласен, это тяжелый материал. Для начинающих как в Perl, так и в FP освоение подхода IO :: Lambda, вероятно, будет очень неприятным. AnyEvent :: HTTP выглядит пригодным для использования, хотя по-прежнему требуется некоторая работа, чтобы ограничить количество параллельных запросов. – ivancho