2010-12-07 12 views
4

Ich habe einige Wartungsaufgaben auf ein paar Perl-Skripten ausgelagert. Eine der Anforderungen besteht darin, ein paar Dutzend Dateien (HTTP) parallel herunterzuladen. Ich schaute auf CPAN für die einfachste Lösung und fand dieses Modul IO::Lambda::HTTP genannt.IO :: Lambda in Perl

Leider habe ich absolut keine Erfahrung mit funktionalen Programmierung (und Anfänger-Erfahrung Perl), so, während ich sehe, dass alle Beispiele funktionieren wie dokumentiert, kann ich nicht wirklich eine von ihnen an meine Bedürfnisse anpassen.

Zum Beispiel kann die Probe, das mit dem Modul kommt:

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

Arbeiten wie in der Werbung, aber ich kann für das Leben von mir nicht vorstellen, wie entweder das ‚Objekt‘ oder ‚impliziten‘ ändern Beispiele N parallelen Instanzen wie folgen aus IO :: Lambda der Synopse zu beschränken:

# 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); 

Kann zeigt mir jemand ein Beispiel dafür, was der Lambda-Code wie angegeben die obige Beschränkung (zB Begrenzung N Instanzen) aussehen würde ?

Auch, was ist der beste Weg zu lernen funktionale Programmierung zu lernen? Es scheint mir völlig fremd zu sein.

Antwort

1

Es gibt andere Optionen als IO :: Lambda für diese Aufgabe, zum Beispiel AnyEvent::HTTP. Siehe this previous SO question.

Obwohl ich mit der funktionalen Programmierung vertraut bin, sieht der obige IO :: Lambda-Beispielcode für mich eher schwer verständlich aus.

+0

Einverstanden, das ist schweres Zeug. Für einen Anfänger in Perl und FP-Mastering wird der IO :: Lambda-Ansatz wahrscheinlich sehr frustrierend sein. AnyEvent :: HTTP sieht verwertbar aus, obwohl es noch einige Arbeit braucht, um die Anzahl der parallelen Anfragen zu begrenzen. – ivancho