# AE + EV + AnyEvent::Http # this is the best one so far, it'll do 34mbps # it's "only" using 80% cpu use strict; use warnings; use EV; use AnyEvent; use AnyEvent::HTTP; sub response { my ($body,$headers) = @_; my $size = length $body; my $url = $headers->{URL}; print "finished $url, $size bytes\n"; } my @urls = ; while(1) { my $url = $urls[int(rand(int(@urls)))]; chomp $url; print "start: $url\n"; http_get $url, \&response; EV::loop EV::LOOP_NONBLOCK; } __DATA__ some urls...the same ones that the Siege test used #### # HTTP::Async # this one will do 20mbps, fastest invokation for me was # perl -w httpasync.pl 0 15 use strict; use warnings; use threads; use threads::shared; use HTTP::Async; use HTTP::Request; use HTTP::Response; my @urls : shared = ; my $numchildren = $ARGV[0]; my $numthreads = $ARGV[1]; print "num children: $numchildren, threads: $numthreads\n"; my $pid = 0; for(my $i = 0; $i < $numchildren; ++$i) { $pid = fork(); if($pid == 0) { last; } else { print "forked $pid\n"; } } $pid = $$; print "pid: $pid\n"; sub fetch { my $tid = shift; my $async = HTTP::Async->new; $async->slots(int(@urls)); my %idurl = (); while(1) { if($async->total_count < $async->slots) { my $url = $urls[int(rand(int(@urls)))]; chomp $url; print "start $pid/$tid: $url\n"; my $id = $async->add(HTTP::Request->new(GET=>$url)); $idurl{$id} = $url; } if($async->not_empty) { my ($resp, $id) = $async->next_response(); if($resp) { my $size = length $resp->content; my $url = $idurl{$id}; print "finish $pid/$tid: $url, $size bytes\n"; delete $idurl{$id}; } } } } my @threads; for(my $i = 0; $i < $numthreads; ++$i) { my $thread = threads->create(\&fetch,$i); push(@threads, $thread); } foreach (@threads) { $_->join(); } __DATA__ some urls... #### # AnyEvent::Curl::Multi, did about 33mbps use strict; use warnings; use EV; use AnyEvent; use AnyEvent::Curl::Multi; use HTTP::Request; my $quit = 0; sub ctrlc { $quit = 1; } $SIG{INT} = \&ctrlc; my @urls = ; my $client = AnyEvent::Curl::Multi->new; $client->max_concurrency(100); $client->reg_cb(response => sub { my ($client, $request, $response, $stats) = @_; my $url = $request->uri; my $size = length $response->content; print "finish: $url, $size bytes\n"; }); $client->reg_cb(error => sub { my ($client, $request, $errmsg, $stats) = @_; # ... }); while(!$quit) { my $url = $urls[int(rand(int(@urls)))]; chomp $url; print "start: $url\n"; my $request = HTTP::Request->new('GET',$url); $client->request($request); EV::loop EV::LOOP_NONBLOCK; } __DATA__ urls... #### # winner! # threads + Furl::HTTP with 10 threads -> 95mbps at 55% cpu # I also tested fork, which was the same, # but threads seemed cleaner use strict; use warnings; use threads; use threads::shared; use Furl; use Perl::Unsafe::Signals; my $quit : shared = 0; sub ctrlc { $quit = 1; } $SIG{INT} = \&ctrlc; my @urls : shared = ; my $numthreads = $ARGV[0]; print "num threads: $numthreads, pid: $$\n"; sub fetch { my $tid = shift; my $furl = Furl::HTTP->new(agent => 'Furl/0.31',timeout => 10); while(!$quit) { my $url = $urls[int(rand(int(@urls)))]; chomp $url; #print "start $tid: $url\n"; my ($ver, $code, $msg, $headers, $body) = $furl->get($url); my $size = length $body; #print "finish $tid: $url, $size bytes\n"; } } my @threads; for(my $i = 0; $i < $numthreads; ++$i) { my $thread = threads->create(\&fetch,$i); push(@threads, $thread); } UNSAFE_SIGNALS { foreach (@threads) { $_->join(); } } __DATA__ urls...