Asynchronous programming FTW!
-
Upload
xsawyer -
Category
Technology
-
view
618 -
download
0
description
Transcript of Asynchronous programming FTW!
ASYNCHRONOUSPROGRAMMING
FTW!(SAWYER X)
DOES THIS SOUND FAMILIAR?"Hi"
"Hi, dad"
"Got a minute?"
"Yes"
"I'm looking for a movieWhere do I start?"
"Go to the cinema website"
"What's the address?"
"www.whatchamacallit.whatever"
"Just a sec..."
...
...
...
...
"Well?"
"Ah! It loaded! What now?"
"Click on new movies"
"OK..."
........
"Well?"
"Loading"
*sounds of clicks*
"OK, now what?"
"Find a movie you want"
"Then what?"
"Click on it, you'll have instructions"
* eternity passes by *
"WELL?!?"
"Just a sec... it's loading..."
/me shoots myself
ILLUSTRATED(USING WWW::MECHANIZE)
$mech>get($cinema_url);if ( $mech>success ) $mech>click('New Movies'); if ( $mech>success ) my @movies = $mech>find_inputs(...)
LET'S TRY THIS AGAIN..."Hi"
"Hi, dad"
"Got a minute?"
"Yes"
"I'm looking for a movieWhat should I do?"
"Go to this website, click on new moviesThen pick a movie, and click on it"
"Thank you"
"You're welcome"
GREAT SUCCESS!
CALLBACKSReference to a codePassed as an argumentCan be called by some other code
sub try_something my $input = shift; my $cb = shift; my $result = some_operation($input);
if ( $result>'status' eq 'OK' ) $cb>( $result>'content' );
try_something( "some random input", sub my $content = shift; say "Successful request says $content!"; );
ILLUSTRATED, ASYNC(USING WWW::MECHANIZE)
$mech>get( $cinema_url, sub $mech>click( 'New Movies', sub $mech>find_inputs( ..., sub my @movies = @_ ) ); );
WHY IS THIS USEFUL?Allow others to decide if something is good or not
my $juno = Juno>new( hosts => [qw<1.1.1.1 2.2.2.2>], checks => FPing => on_success => sub my ( $juno, $host, $data ) = @_; my ( $ip, $loss, $avg ) = $juno>analyze_ping_result( $data>'stderr', );
$self>set_host( $host, $avg ); ,
on_fail => sub my ( $juno, $host ) = @_;
$self>delete_host($host); , );
WHY IS THIS USEFUL?Allow others to decide if something is good or notAllow easy stepping
Algorithm::Diff::Callbackuse Algorithm::Diff::Callback qw<diff_arrays diff_hashes>;
diff_arrays( \@old_family_members, \@new_family_members, sub print 'Happy to hear about ', shift , sub print 'Sorry to hear about ', shift ,);
diff_hashes( \%old_details, \%new_details, sub say 'Lost ', shift , sub say 'Gained ', shift , sub my ( $key, $before, $after ) = @_; say "$key changed from $before to $after"; ,);
WHY IS THIS USEFUL?Allow others to decide if something is good or notAllow easy steppingAllow control by other process (a type of IOC)Allow asynchronous code
THE EVENT LOOPCreate loopRegister eventsRun themLet the user keep registering new events
my %events = (...);
while (1) foreach my $event ( keys %events ) $event>();
my %events; %events = (...);
while (1) foreach my $event ( keys %events ) $event>();
while (1) foreach my $event ( keys %events ) if ( $events$event'time' <= time ) $events$event'code'>();
sub add_event my ( $time, $code ) = @_; $events$id'time' = $time; $events$id'code' = $code; $id++;
EVENT TYPESTimers (one-time, recurring, sleep replacement)I/O (input output, including networking)
FUCK TALKLET'S GO PROGRAMMING
IO::ASYNCLoop interface: IO::Async::LoopYou can connect to hosts using itYou can add listeners to it (handles, sockets, etc.)Explicitly call "run" when ready
use IO::Async::Stream;use IO::Async::Loop; my $loop = IO::Async::Loop>new;
$loop>connect( host => "some.other.host", service => 12345, socktype => 'stream', on_stream => sub ... , on_resolve_error => sub die "Cannot resolve $_[1]" ,
on_connect_error => sub die "Cannot connect $_[0] failed $_[1]" ,);
$loop>run;
on_stream => sub my ( $stream ) = @_;
$stream>configure( on_read => sub my ( $self, $buffref, $eof ) = @_;
while( $$buffref =~ s/(.*\n)// ) say "Received a line $1";
return 0; );
$stream>write('An initial line here');
$loop>add($stream);
ANOTHER EXAMPLE
Oh hai parallel HTTP GET!
$ perl MIO::Async MNet::Async::HTTP E ' IO::Async>add( my $http = Net::Async::HTTP>new ); say for IO::Async>await_all( map $http>get($_) )' > listofURLs.txt
POELoop interface: POE::KernelRuns "sessions" (POE::Session)Each session is a context of eventsEach session has an ID and heapCall events in a current or different sessionExplicitly call POE::Kernel->run when ready
POEuse POE; # Autoincludes POE::Kernel and POE::Session.
# ... define callbacks subs (next slide) ...
for (1..10) POE::Session>create( inline_states => _start => \&handler_start, increment => \&handler_increment, _stop => \&handler_stop, );
POE::Kernel>run();
sub handler_start my ( $kernel, $heap, $session ) = @_[ KERNEL, HEAP, SESSION ]; say "Session ", $session>ID, " has started"; $heap>'count' = 0; $kernel>yield('increment');
sub handler_increment my ( $kernel, $heap, $session ) = @_[ KERNEL, HEAP, SESSION ]; say "Session ", $session>ID, " counted to ", ++$heap>'count'; $kernel>yield('increment') if $heap>'count' < 10;
sub handler_stop say "Session ", $_[SESSION]>ID, " has stopped";
sub handler_start my ( $kernel, $heap, $session ) = @_[ KERNEL, HEAP, SESSION ]; say "Session ", $session>ID, " has started"; $heap>'count' = 0; $kernel>yield('increment');sub handler_increment my ( $kernel, $heap, $session ) = @_[ KERNEL, HEAP, SESSION ]; say "Session ", $session>ID, " counted to ", ++$heap>'count'; $kernel>yield('increment') if $heap>'count' < 10;sub handler_stop say "Session ", $_[SESSION]>ID, " has stopped.\n";for (1..10) POE::Session>create( inline_states => _start => \&handler_start, increment => \&handler_increment, _stop => \&handler_stop, );POE::Kernel>run();
MORE CONDENSEDuse POE;
for (1..10) my $count = 0;
POE::Session>create( inline_states => _start => sub say "Session ", $_[SESSION]>ID, " has started"; POE::Kernel>yield('increment'); , increment => sub POE::Kernel>yield('increment') if ++$count < 10; say "Session ", $_[SESSION]>ID, " counted to $count"; , _stop => sub say "Session ", $_[SESSION]>ID, " has stopped"; , );
POE::Kernel>run();
REFLEXWritten by author of POE"How POE would be written if I had Moose back then"Stresses composability, reusabilityIncludes plenty of additional roles
USING MOOSE package App; use Moose; extends 'Reflex::Base'; use Reflex::Interval; use Reflex::Trait::Watched 'watches'; watches ticker => ( isa => 'Reflex::Interval', setup => interval => 1, auto_repeat => 1 , ); sub on_ticker_tick say 'tick at ', scalar(localtime), '...'; exit App>new()>run_all();
COMPLEX? TRY THIS...use Reflex::Interval; my $t = Reflex::Interval>new( interval => 1, auto_repeat => 1, on_tick => sub say 'timer ticked' ,); $t>run_all();
ANYEVENTAnyEvent is very thin and very fastWas written to support as many loops as possible... that conform to the author's rules of compatibilityDoes not use a loop handler, simply runsDoes use conditional variablesHas AE for faster performance
use AnyEvent;my $count = 0;my $cv = AnyEvent>condvar;my $t = AnyEvent>timer( after => 2, interval => 0.6, cb => sub say 'The time is now: ', AnyEvent>now; ++$count == 10 and $cv>send; ,);
$cv>recv;
my $w; $w = AnyEvent>io( fh => \*STDIN, poll => 'r', cb => sub chomp ( my $input = ); say "read: $input"; undef $w; ,);
USAGES OF ASYNCHRONOUS CODEGUIServices (HTTP/SMTP/etc.)PerformanceOff-loading tasks
THANK YOU