2010-12-07 30 views
4

J'ai été déchargé de certaines tâches de maintenance sur un couple de scripts Perl. L'une des exigences est de télécharger quelques dizaines de fichiers (HTTP) en parallèle. Je suis allé chercher CPAN pour la solution la plus simple et trouvé ce module appelé IO::Lambda::HTTP. Malheureusement, je n'ai absolument aucune expérience de la programmation fonctionnelle (et de l'expérience Perl débutant), alors même si je vois que tous les exemples fonctionnent comme documentés, je ne peux en modifier aucun pour répondre à mes besoins.IO :: Lambda in Perl

Par exemple, l'échantillon qui vient avec le module:

#!/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; 
} 

fonctionne comme annoncé, mais je ne peux pas pour la vie de me comprendre comment modifier soit le « objet » ou « implicite » exemples à être limités aux cas N parallèles comme le suivant de IO :: synopsis de 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); 

que quelqu'un peut me montrer un exemple de ce que le code lambda ressemblerait compte tenu de la contrainte ci-dessus (par exemple limite aux instances N) ?

En outre, quelle est la meilleure façon de commencer à apprendre la programmation fonctionnelle? Cela me semble totalement étranger.

Répondre

1

Il existe d'autres options que IO :: Lambda pour cette tâche, par exemple AnyEvent::HTTP. Voir this previous SO question.

Même si je suis familier avec la programmation fonctionnelle, l'exemple de code IO :: Lambda ci-dessus semble assez difficile à comprendre pour moi.

+0

D'accord, ce sont des choses lourdes. Pour un débutant en maîtrise Perl et FP, l'approche IO :: Lambda sera probablement très frustrante. AnyEvent :: HTTP semble utilisable, bien qu'il ait encore besoin de travail pour limiter le nombre de requêtes parallèles. – ivancho