X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=slides.html;h=745bf127db87dedbe3ae370155dfe02d9c935c1b;hb=HEAD;hp=161851a13bf2d9f2c16eb9e5a8068a2ae94d68cc;hpb=afb7de1b61d2bf725c70e8f6be00592f1b762e82;p=chaz%2Ftalk-event-driven-programming-in-perl diff --git a/slides.html b/slides.html index 161851a..745bf12 100644 --- a/slides.html +++ b/slides.html @@ -444,6 +444,12 @@ while (1) { } ``` +??? +Of course, you don't actually need to know anything about which syscalls are used and how a reactor actually works to do +event-driven programming. (and if any of this is going over your head, that's fine.) + +But I'm covering it because I think it's good for you. + --- class: ex-basicreactor2 @@ -530,12 +536,354 @@ By my count there are four main front ends. The benefit of using one of these rather than the reactors themselves is that your code will automatically work with any of a number of supported reactors. +--- +class: ex-poe + +## `POE` + +```perl +use POE; +use Time::HiRes qw(time); + +POE::Session->create( + inline_states => { + _start => sub { + $_[KERNEL]->delay(tick => 5); + }, + + tick => \&handle_timer_event, + }, +); + +POE::Kernel->run; +``` + +??? POE: - The oldest, released 1998 - Parallel processing was it's primary use. -- Everything center by the "wheel" (loop). -- You add "handles" to the object. -- Each type of handle has certain events it knows how to handle. + +--- +class: ex-poe + +## `POE` + +```perl +*use POE; +use Time::HiRes qw(time); + +POE::Session->create( + inline_states => { + _start => sub { + $_[KERNEL]->delay(tick => 5); + }, + + tick => \&handle_timer_event, + }, +); + +POE::Kernel->run; +``` + +??? +Using `POE` will implicitly load all the modules you'll need to actually do anything. +- In this case, `POE::Session` and `POE::Kernel`. + +--- +class: ex-poe + +## `POE` + +```perl +use POE; +use Time::HiRes qw(time); + +POE::Session->create( + inline_states => { + _start => sub { + $_[KERNEL]->delay(tick => 5); + }, + + tick => \&handle_timer_event, + }, +); + +*POE::Kernel->run; +``` + +??? +Run the reactor. + +In POE, the kernel is the thing that manages processes AKA sessions. + +--- +class: ex-poe + +## `POE` + +```perl +use POE; +use Time::HiRes qw(time); + +*POE::Session->create( +* inline_states => { +* _start => sub { +* $_[KERNEL]->delay(tick => 5); +* }, +* +* tick => \&handle_timer_event, +* }, +*); + +POE::Kernel->run; +``` + +??? + +Sessions can be created to do stuff. + +--- +class: ex-ioasync + +## `IO::Async` + +```perl +use IO::Async::Loop; +use IO::Async::Timer::Countdown; + +my $loop = IO::Async::Loop->new; + +my $timer = IO::Async::Timer::Countdown->new( + delay => 5, # seconds + on_expire => \&handle_timer_event, +); +$timer->start; + +$loop->add($timer); + +$loop->run; +``` + +--- +class: ex-ioasync + +## `IO::Async` + +```perl +use IO::Async::Loop; +use IO::Async::Timer::Countdown; + +*my $loop = IO::Async::Loop->new; + +my $timer = IO::Async::Timer::Countdown->new( + delay => 5, # seconds + on_expire => \&handle_timer_event, +); +$timer->start; + +$loop->add($timer); + +$loop->run; +``` + +??? +Create the loop +- IO::Async doesn't seem to have a concept of a "default" loop. + - The user has control over starting the loop, as usual, but it does mean that modules can't really register + themselves. + +--- +class: ex-ioasync + +## `IO::Async` + +```perl +use IO::Async::Loop; +use IO::Async::Timer::Countdown; + +my $loop = IO::Async::Loop->new; + +my $timer = IO::Async::Timer::Countdown->new( + delay => 5, # seconds + on_expire => \&handle_timer_event, +); +$timer->start; + +*$loop->add($timer); + +*$loop->run; +``` + +??? +Add your handler to the loop, and of course run the loop. + +--- +class: ex-ioasync + +## `IO::Async` + +```perl +use IO::Async::Loop; +use IO::Async::Timer::Countdown; + +my $loop = IO::Async::Loop->new; + +my $timer = IO::Async::Timer::Countdown->new( + delay => 5, # seconds + on_expire => \&handle_timer_event, +); +*$timer->start; + +$loop->add($timer); + +$loop->run; +``` + +??? +Remember to actually start your timer! The timer facilities in other loops seem to do this for you, but this does give you more control. +- For example, you can call `reset` on the timer to set it back it it's initial delay value. + +--- +class: ex-mojoioloop + +## `Mojo::IOLoop` + +```perl +use Mojo::IOLoop; + +Mojo::IOLoop->timer(5 => \&handle_timer_event); + +Mojo::IOLoop->start if ! Mojo::IOLoop->is_running; +``` + +--- +class: ex-mojoioloop + +## `Mojo::IOLoop` + +```perl +use Mojo::IOLoop; + +*Mojo::IOLoop->timer(5 => \&handle_timer_event); + +Mojo::IOLoop->start if ! Mojo::IOLoop->is_running; +``` + +??? +Create the timer... easy. + +--- +class: ex-mojoioloop + +## `Mojo::IOLoop` + +```perl +use Mojo::IOLoop; + +Mojo::IOLoop->timer(5 => \&handle_timer_event); + +*Mojo::IOLoop->start if ! Mojo::IOLoop->is_running; +``` + +??? +And start the loop. Very easy. + +- `Mojo::IOLoop` provides methods for creating network clients and servers without much code. +- Doesn't seem to have support for demultiplexing signals, but if this is important you can probably set that up + directly with the `EV` reactor back end. + +--- +class: ex-anyevent + +## `AnyEvent` + +```perl +use EV; +use AE; + +my $timer = AE::timer(5, 0 => \&handle_timer_event); + +EV::run(); +``` + +--- +class: ex-anyevent + +## `AnyEvent` + +```perl +*use EV; +use AE; + +my $timer = AE::timer(5, 0 => \&handle_timer_event); + +*EV::run(); +``` + +--- +class: ex-anyevent + +## `AnyEvent` + +```perl +*use Glib; +use AE; + +*my $loop = Glib::MainLoop->new; + +my $timer = AE::timer(5, 0 => \&handle_timer_event); + +*$loop->run; +``` + +--- +class: ex-anyevent + +## `AnyEvent` + +```perl +use Glib; +use AE; + +my $loop = Glib::MainLoop->new; + +*my $timer = AE::timer(5, 0 => \&handle_timer_event); + +$loop->run; +``` + +??? +Create your timer. + +By the way, the second argument to `AE::timer` represents the interval if you want a periodic timer. + +- Remember to save the return value of setting up your timer and other handles. + - That thing is actually called a "watcher", and the destruction of watcher objects is how event handlers get + unregistered. + +`AnyEvent` technically has two APIs. This is the "simplified" API. + +--- +class: ex-anyevent + +## `AnyEvent` + +```perl +use Glib; +*use AnyEvent; + +my $loop = Glib::MainLoop->new; + +*my $timer = AnyEvent->timer( +* after => 5, +* cb => \&handle_timer_event, +*); + +$loop->run; +``` + +??? +This is what the "complicated" API looks like. --- name: not-all-roses @@ -861,7 +1209,60 @@ my $eventual_future = repeat { ``` --- -## Events in the world +class: center, middle + +## Final thoughts + +--- +class: center, middle + +### Proactor pattern + +??? +We've gone over the Reactor pattern quite a bit, and for good reason. + +It's the predominant implementation of event-driven code in userspace apps. + +But you should also know about the Proactor pattern. + +It's basically the same as the reactor pattern except the event handlers perform asynchronous operations. +- Can be done using special kernel facilities +- or by keeping a thread pool. + +One thing to keep in mind about the reactor pattern is that any sort of blocking that occurs by any event handlers will +slow everything down quite a bit. The proactor pattern can help avoid problems. + +--- +class: center, middle + +### Event-driven programming architecture + +??? +Making your apps reactive and able to generate and respond to events is the tip of a very large iceburg. + +- Pubsub systems can be used to distribute events at a massive scale. +- Message queues are components that can be plugged in to provide guaranteed delivery of events. + +Once your programs are event-driven, they're ready to be plugged into a whole world of other services. + +--- +class: center, middle + +### Lots of interconnected devices + +??? +This concept has a trendy name, but I can't say it because I've swarn off buzzwords. + +Event-driven programming and architecture is used as a foundation for building APIs and applications that scale, if +that's important to you. + +You can avoid coupling: When one of your devices has an event, it just needs to notify your world of devices and let the +devices decide what to do. + +For example, if your car has connected sensors, it can notify your devices when you leave the car. Then your phone can +receive that event and notify you that you left your kid in the car. + +So there are a lot of cool applications for this stuff. --- class: center, middle