asynchronous programming ftw! 2 (with anyevent)
DESCRIPTION
This is a revamped Asynchronous Programming FTW talk, given at YAPC::NA 2013, Cluj.pm, and AmsterdamX.pm.TRANSCRIPT
![Page 1: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/1.jpg)
AsynchronousAsynchronous
ProgrammingProgramming
FTW!FTW!
(Sawyer X)
@PerlSawyer
Theory
Practice
![Page 2: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/2.jpg)
TheoryTheory
We think in non-blocking terms
We act in non-blocking terms
We program in blocking terms
An example? Sure!
![Page 3: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/3.jpg)
The exampleThe example
use LWP::UserAgent;
my @urls = ( 'https://duckduckgo.com', 'http://cluj.pm', 'http://telaviv.pm.org',);
my $ua = LWP::UserAgent->new;foreach my $url (@urls) { my $res = $ua->get($url); say $res->decoded_content;}
![Page 4: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/4.jpg)
Problem?Problem?
Wait on each URL
Ineffecient waste of time
Pointless
Senseless
CRIME AGAINST HUMANITY
(maybe just ineffecient)
![Page 5: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/5.jpg)
How we thinkHow we think
Nothing to work on? Defer to later!
Like cooking!
![Page 6: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/6.jpg)
Making dinnerMaking dinner
Boil water. Wait? No! Salad time!
(water gets deferred to later)
Cook potatoes. Wait? No! Sauce time!
(potatoes get deferred to later)
We think and act non-blocking
![Page 7: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/7.jpg)
TIMTOWTDITIMTOWTDI
Forks
Threads
Event-loops <- this talk
![Page 8: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/8.jpg)
Event loop?Event loop?
Single thread, single process
Like a big while(1) {}Heavy usage of code references
No real race conditions
No locking, semaphores, etc.
Can yield better speed
But... nothing can be blocking! (I/O)
![Page 9: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/9.jpg)
Event loops in PerlEvent loops in Perl
POE
Reflex
IO::Async
IO::Lambda
Qt, GTK, Tk, Glib, Cocoa::EventLoop, EV, FLTK, Irssi
AnyEvent <- this talk
![Page 10: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/10.jpg)
AnyEventAnyEvent
Light-weight
Fast
Very fast
Slim interface
Good support for other event loops
Lots of modules
![Page 11: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/11.jpg)
PracticePractice
Cooking with AnyEventCooking with AnyEvent
(timers)(timers)
use AnyEvent;say '>> Water boiling...';my $water = AnyEvent->timer( after => 5*60, cb => sub { say '<< Water boiled!'; say '>> Potatos being prepared...'; my $potatoes; $potatoes = AnyEvent->timer( after => 10*60, cb => sub { undef $potatoes; say '<< Potatos ready!'; } );} );
say '>> Salad being prepared...';my $salad = AnyEvent->timer( after => 6*60, cb => sub { say '<< Salad ready!'; say '>> Sauce being prepared...'; my $sauce; $sauce = AnyEvent->timer( after => 12*60, cb => sub { undef $sauce; say '<< Sauce ready!'; } );} );
![Page 12: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/12.jpg)
Water - 5 minutes
Potatos - 10 minutes after water
Salad - 6 minutes
Sauce - 12 minutes after salad
Water, salad, potatoes, sauce
>> Water boiling...>> Salad being prepared...<< Water boiled!>> Potatos being prepared...<< Salad ready!>> Sauce being prepared...<< Potatos ready!<< Sauce ready!
![Page 13: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/13.jpg)
Condition variablesCondition variables
A condition waiting to be fulfilled
Starting at false, hoping to get to trueHelps waiting for other events to finish
Call ->recv() to wait for stuff to finish
Call ->send() when finished doing your stuff
Without condition variables, we reach the end of programs
We reach the end == program closes
Program closes == our code doesn't get executed
Our code doesn't get executed == we get executed!
![Page 14: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/14.jpg)
Simple exampleSimple example
use AnyEvent;
my $count = 1;my $cv = AnyEvent->condvar;my $timer = AnyEvent->timer( interval => 1, cb => sub { say "Count: $count"; $count++ == 5 and $cv->send; },);
$cv->recv;say 'We counted to 5!';
![Page 15: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/15.jpg)
Bigger exampleBigger example
my $cv = AnyEvent->condvar;my $water = AnyEvent->timer( after => 5*60, cb => sub { my $potatoes; $potatoes = AnyEvent->timer( after => 10*60, cb => sub { undef $potatoes; } );} );
my $salad = AnyEvent->timer( after => 6*60, cb => sub { my $sauce; $sauce = AnyEvent->timer( after => 12*60, cb => sub { undef $sauce; $cv->send; } );} );
$cv->recv;
![Page 16: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/16.jpg)
Better example :: LWPBetter example :: LWP
use LWP::UserAgent;
my @urls = ( 'https://whatismyip.com', 'http://checkip.dyndns.org', 'http://wtfismyipaddress.org',);
my $ua = LWP::UserAgent->new;foreach my $url (@urls) { my $res = $ua->get($url); say $res->decoded_content;}
![Page 17: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/17.jpg)
Better example :: AnyEventBetter example :: AnyEvent
use AnyEvent;use AnyEvent::HTTP;
my $cv = AnyEvent->condvar;foreach my $url (@urls) { $cv->begin; http_get $url, sub { my $body = shift; say $body; $cv->end; }}
$cv->recv;
![Page 18: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/18.jpg)
POP QUIZ TIME!POP QUIZ TIME!
A few examples
Spot the error(s) and get a prize
Available prizes: handshake, high five, hug, kiss
(not necessarily from me)
![Page 19: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/19.jpg)
Round 1Round 1
use AnyEvent;use AnyEvent::HTTP;
http_post $url, $body, sub { say 'Successfully made an API call to do something cool!';};
# wait for all events to finishAnyEvent->condvar->recv;
![Page 20: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/20.jpg)
Round 2Round 2
use AnyEvent;
my $timer = AnyEvent->timer( interval => 5, cb => sub { sleep 1; say 'Bwahaha!'; });
![Page 21: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/21.jpg)
Round 3Round 3
use AnyEvent;my $cv = AnyEvent->condvar;my $player1 = AnyEvent->timer( after => 3.7, cb => sub { say 'Player 1 joins the game!'; $cv->send; },);my $player2 = AnyEvent->timer( after => 7.2, cb => sub { say 'Player 2 joins the game!'; $cv->send; },);$cv->recv;
![Page 22: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/22.jpg)
Round 4Round 4
use AnyEvent; use HTTP::Tiny;my $cv = AnyEvent->condvar;$cv->begin for 1 .. 2;my $player1 = AnyEvent->timer( after => 3.7, cb => sub { say 'Player 1 joins the game! Alerting server!'; my $res = HTTP::Tiny->new->get('http://server:3030/add/1'); $res->{'success'} or die 'Failed to insert player 1 to game!'; $cv->end; },);my $player2 = AnyEvent->timer( after => 7.2, cb => sub { say 'Player 2 joins the game!'; $cv->end; },);$cv->recv;
![Page 23: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/23.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
![Page 24: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/24.jpg)
WWW::xkcdWWW::xkcd
use WWW::xkcd;my $xkcd = WWW::xkcd->new;
$xkcd->fetch( sub { my ( $img, $comic ) = @_; say "Today's comic is titled: ", $comic->{'title'}; ...} );
![Page 25: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/25.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
PSGI/Plack server
![Page 26: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/26.jpg)
TwiggyTwiggy
use Twiggy::Server;my $app = sub { # PSGI app};
my $server = Twiggy::Server->new(...);$server->register_service($app);
AnyEvent->condvar->recv;
![Page 27: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/27.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
PSGI/Plack server
Async AWS EC2 interface
![Page 28: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/28.jpg)
AnyEvent::EC2::TinyAnyEvent::EC2::Tiny
use AnyEvent::EC2::Tiny;my $ec2 = AnyEvent::EC2::Tiny->new(...);my $xml = $ec2->send( 'RegionName.1' => 'us-east-1', Action => 'DescribeRegions', success_cb => sub { my $xml = shift; # prints ec2.us-east-1.amazonaws.com say $xml->{'regionInfo'}{'item'}[0]{'regionEndpoint'}; }, fail_cb => sub { my $error = shift; ... },);
![Page 29: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/29.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
PSGI/Plack server
Async AWS EC2 interface
Monitoring framework
![Page 30: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/30.jpg)
JunoJuno
use Juno;my $juno = Juno->new( hosts => [ 'server1', 'server2' ], interval => 10, checks => { HTTP => { headers => { { 'Host', 'example.com' }, },
on_result => sub { my $result = shift; ... }, }, },);
![Page 31: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/31.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
PSGI/Plack server
Async AWS EC2 interface
Monitoring framework
Real-time network path resolution
![Page 32: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/32.jpg)
SIP RouteSIP Route
use AnyEvent;use Anyevent::Util 'fork_call';use AnyEvent::Socket;use AnyEvent::Handle;use Data::Dump 'dump';
my $tcp_server_guard = tcp_server '127.0.0.1', 2020, sub { my ($fh) = @_; my $handle = AnyEvent::Handle->new( fh => $fh ); $handle->push_read( line => sub {...} );};
![Page 33: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/33.jpg)
my ( $hdl, $target ) = @_;
if ( ! defined $target ) { $hdl->push_write($default_route); $hdl->destroy; return;}
chomp $target;
if ( ! exists $data{$target} ) { $hdl->push_write($default_route); $hdl->destroy; return;}
![Page 34: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/34.jpg)
my @sorted = sort { $data{$target}{$a} <=> $data{$target}{$b} } keys %{ $data{$target} };
$hdl->push_write( $sorted[0] );
$hdl->destroy;
![Page 35: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/35.jpg)
foreach my $target (@targets) { foreach my $iface (@interfaces) { my $cmd = "sipsak --sip-uri=sip:$target -D $timeout -X $iface"; push @timers, AE::timer $start_after, $check_every, sub { my $time = AE::now; fork_call { system "$cmd >/dev/null 2>&1"; return $? >> 8; } sub { my $exit = shift; ( $exit == 0 || $exit == 1 ) or return delete $data{$target}{$iface}; $data{$target}{$iface} = AE::now - $time; }; }; }}
AE::cv->recv;
![Page 36: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/36.jpg)
if ($verbose) { push @timers, AE::timer 5, 5, sub { dump \%data };}
![Page 37: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/37.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
PSGI/Plack server
Async AWS EC2 interface
Monitoring framework
Real-time network path resolution
API interfaces to services
![Page 38: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/38.jpg)
AnyEvent::RiakAnyEvent::Riak
use AnyEvent::Riak;
my $riak = AnyEvent::Riak->new( host => 'http://127.0.0.1:8098', path => 'riak',);
$riak->list_bucket( 'mybucket', {props => 'true', keys => 'false'}, sub { my $res = shift; ... });
![Page 39: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/39.jpg)
AnyEvent::SNMPAnyEvent::SNMP
use AnyEvent::SNMP;use Net::SNMP;
my $cv = AnyEvent->condvar;Net::SNMP->session( -hostname => "127.0.0.1", -community => "public", -nonblocking => 1)->get_request( -callback => sub { $cv->send (@_) } );
my @result = $cv->recv;
![Page 40: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/40.jpg)
AnyEvent::XMLRPCAnyEvent::XMLRPC
use AnyEvent::XMLRPC;
my $serv = AnyEvent::XMLRPC->new( methods => { 'echo' => \&echo, },);
![Page 41: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/41.jpg)
AnyEvent::DNSAnyEvent::DNS
use AnyEvent::DNS;
my $cv = AnyEvent->condvar;AnyEvent::DNS::a "www.google.ro", $cv;
# later...my @addrs = $cv->recv;
![Page 42: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/42.jpg)
AnyEvent::TwitterAnyEvent::Twitter
my $ua = AnyEvent::Twitter->new( consumer_key => 'consumer_key', consumer_secret => 'consumer_secret', access_token => 'access_token', access_token_secret => 'access_token_secret',);
my $cv = AnyEvent->condvar;
# GET request$cv->begin;$ua->get( 'account/verify_credentials', sub { my ($header, $response, $reason) = @_;
say $response->{screen_name}; $cv->end;} );
![Page 43: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/43.jpg)
AnyEvent::GraphiteAnyEvent::Graphite
my $graphite = AnyEvent::Graphite->new( host => '127.0.0.1', port => '2003',);
$graphite->send("a.b.c.d", $value, $timestamp);
![Page 44: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/44.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
PSGI/Plack server
Async AWS EC2 interface
Monitoring framework
Real-time network path resolution
API interfaces to services
Find matching special actors in TV series
![Page 45: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/45.jpg)
Actor matchesActor matches
use AnyEvent; use AnyEvent::HTTP;my $base = 'http://www.imdb.com/title';my %titles = ( tt1196946 => { name => 'Mentalist, the' }, tt1219024 => { name => 'Castle' }, tt0773262 => { name => 'Dexter' }, tt0491738 => { name => 'Psych' }, tt0247082 => { name => 'CSI Las Vegas' }, tt0458253 => { name => 'Closer, the' },);
# DON'T PARSE HTML WITH REGEX!!!!1127my $episode_regex = qr{...};my $cast_regex = qr{...};
![Page 46: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/46.jpg)
# Fetching number of seasons for each titlemy $cv = AE::cv;foreach my $title_id ( keys %titles ) { my $title = $titles{$title_id}{'name'}; print "[$title] Fetching number of seasons.\n";
my $url = "$base/$title_id/"; my $regex = qr{/title/$title_id/episodes\?season=([0-9]+)}; $cv->begin; http_get $url, sub { my ( $body, $hdr ) = @_; my @found = $body =~ /$regex/mg; $titles{$title_id}{'episodes'}{$_} = [] for @found; $cv->end; };}$cv->recv;
![Page 47: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/47.jpg)
# fetching the list of episodes for each seasonforeach my $title_id ( keys %titles ) { my $cv = AE::cv; foreach my $season ( keys %{ $titles{$title_id}{'episodes'} } ) { my $title = $titles{$title_id}{'name'}; print "[$title] [Season $season] fetching episodes\n";
my $season_url = "$base/$title_id/episodes?season=$season"; $cv->begin; http_get $season_url, sub { my ( $body, $hdr ) = @_; my @found = $body =~ /$episode_regex/mg;
while (@found) { my $id = shift @found; my $name = shift @found;
![Page 48: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/48.jpg)
foreach my $title_id ( keys %titles ) { my $title = $titles{$title_id}{'name'};
foreach my $season ( keys %{ $titles{$title_id}{'episodes'} } ) { my @episodes = @{ $titles{$title_id}{'episodes'}{$season} };
print "[$title] [$season] Fetching cast for season $season\n"; my $cv = AE::cv; foreach my $episode_id (@episodes) { print " -> [$title] [$season] $episode_id\n"; my $url = "$base/$episode_id/fullcredits";
$cv->begin; http_get $url, sub { my ( $body, $hdr ) = @_; my @found = $body =~ /$cast_regex/mg;
![Page 49: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/49.jpg)
print "Populating actors\n";my %actors = ();foreach my $title_id ( keys %titles ) { my $title = $titles{$title_id}{'name'};
foreach my $cast_sets ( @{ $titles{$title_id}{'cast'} } ) { my ( $name, $role ) = @{$cast_sets}; $actors{$name}{$title} = $role; }}
![Page 50: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/50.jpg)
print "Cross referencing\n";foreach my $name ( keys %actors ) { scalar keys %{ $actors{$name} } > 1 or next;
my @where = (); foreach my $title ( keys %{ $actors{$name} } ) { my $role = $actors{$name}{$title}; push @where, "$title ($role)"; }
printf "Actor $name appeared in %s\n", join ', ', @where;}
![Page 51: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/51.jpg)
Some dataSome data
6 TV series
42 total seasons
1,510 total episodes
6,484 total actors
7,493 total roles
380,520 total requests (6 * 42 * 1,510)
~ 2s/req = 761,040s = 12,684m = 211h = 8.8 days
Time to run (incl. analysis) with AnyEvent: 6 minutes
Matches found... 1,095!
![Page 52: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/52.jpg)
Actor Michael Patrick McGill appeared in:
CSI Las Vegas (Ruben Caster)
Dexter (Troy)
Actor Robert Esser appeared in:
CSI Las Vegas (Waiter)
Castle (Officer #2 (uncredited))
Actor Andre Alexsen appeared in:
Closer, the (Adam)
Mentalist, the (CA State Govenor (uncredited))
Actor Becky O'Donohue appeared in:
CSI Las Vegas (Ava Rendell)
Mentalist, the (Sasha)
Psych (Molly Gogolack)
![Page 53: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/53.jpg)
Mark PellegrinoMark Pellegrino
Tom Dempsey / Tom Dempsey III in Castle
Gavin Q. Baker III in The Closer
Bruno Curtis in CSI Last Vegas
Paul Bennett in Dexter
Von McBride in The Mentalist
Most accomplishedMost accomplished
cross-actorcross-actor
![Page 54: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/54.jpg)
Stuff to do with AnyEventStuff to do with AnyEvent
xkcd interface
PSGI/Plack server
Async AWS EC2 interface
Monitoring framework
Real-time network path resolution
API interfaces to services
Find matching special actors in TV series
Whole lot of other awesome stuff
(which I'm not gonna show you now)
![Page 55: Asynchronous Programming FTW! 2 (with AnyEvent)](https://reader034.vdocuments.mx/reader034/viewer/2022051322/53f9ba008d7f72b82e8b4b5b/html5/thumbnails/55.jpg)
Thank youThank you