X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=slides.html;h=51f91018b47b58dc661ea16ec0f31ef6e68920f0;hb=309c1da6df9319b3bcd760fd3073bafeda9faf09;hp=9eae8008ce65f65a0a2751af948d93738c50c4ee;hpb=1e5589cbb1518565f28a66bafd4882eec1d9acd5;p=chaz%2Ftalk-event-driven-programming-in-perl diff --git a/slides.html b/slides.html index 9eae800..51f9101 100644 --- a/slides.html +++ b/slides.html @@ -54,6 +54,9 @@ my $pizza = prepare_and_bake($order, $ingredentials); print($pizza); ``` +??? +But some programs are long-lived. + --- ## Event-driven programs @@ -68,8 +71,11 @@ At it's core, event-driven programming is this simple. But there are some complications and things to knows, which is why this talk exists. --- +name: graph-eventloop class: center, middle +## Event loop + ![Event loop](img/eventloop.svg) ??? @@ -364,9 +370,30 @@ class: syscalls ### syscalls - [`pause`](http://man.he.net/man2/pause) - Sleeps until signal + +-- - [`select`](http://man.he.net/man2/select), [`poll`](http://man.he.net/man2/poll), [`epoll`](http://man.he.net/man7/epoll), [`kqueue`](https://www.freebsd.org/cgi/man.cgi?format=ascii&sektion=2&query=kqueue) - Monitor multiple file descriptors + +-- - [`clock_gettime`](http://man.he.net/man2/clock_gettime) - What time is it now? +--- + +## Reactor pattern + +.big[ +- Queues events asynchronously. +- Demultiplexes and dispatches synchronously. +] + +--- +name: graph-reactor +class: center, middle + +## Reactor pattern + +![Reactor](img/reactor.svg) + --- class: ex-basicreactor @@ -386,6 +413,25 @@ while (1) { } ``` +--- +class: ex-basicreactor + +## The basic reactor + +```perl +our $timers = [...]; +our $io_handles = [...]; + +while (1) { + my $next_timer = find_next_timer($timers); + +* poll($io_handles, $next_timer->time_from_now); + + handle_ready_io_handles($io_handles); + handle_expired_timers($timers); +} +``` + --- ## Reactor examples on CPAN @@ -399,6 +445,149 @@ while (1) { - [`Mojo::Reactor::Poll`](https://metacpan.org/source/Mojo::Reactor::Poll) ] +--- +name: not-all-roses +class: center, middle + +![Thorns](img/thorn.jpg) + +## Watch out for the thorns... + +??? +There are some special considerations you need to take when writing event-driven code. + +--- +class: center, middle + +## Exceptions for error handling + +--- +class: center, middle + +### Problem: No exception handler up the call stack + +--- +class: ex-exceptions + +## Rule: Don't die/throw in event handlers. + +-- +### Error callback pattern + +```perl +do_something_asynchronously( + callback => sub { ... }, + on_error => sub { ... }, +); +``` + +--- +class: ex-exceptions + +## Rule: Don't die/throw in event handlers. + +### Use promises + +```perl +my $promise = do_something_asynchronously(); + +$promise->on_done(sub { ... }); +$promise->on_fail(sub { ... }); +``` + +--- +class: center, middle + +## `SIGPIPE` + +--- +class: sigpipe +## `SIGPIPE` + +- Sent to your program when it writes to a pipe that was closed. + +-- +- Default signal handler terminates the program. + +--- +class: ex-sigpipe + +## Solution: Ignore `SIGPIPE` + +```perl +$SIG{PIPE} = 'IGNORE'; +``` + +??? +Some event loops do this for you. + +-- +.big[ +Look for `EPIPE` from syscalls (like [`write`](http://man.he.net/man2/write)) instead. + +(You *are* checking return codes from your system calls... right?) +] + +--- +class: center, middle + +## Use [`Future::AsyncAwait`](https://metacpan.org/pod/Future::AsyncAwait). + +??? +If you have used JavaScript recently, you may have used its "async/await" feature to clean up your non-blocking code. + +--- +class: center, middle + +### Yes, Perl can do it, too! + +--- +class: ex-asyncawait + +## Without async and await + +```perl +use Future; + +sub do_two_things { + return do_first_thing()->then(sub { + my $first = shift; + + return do_second_thing($first)->then(sub { + my $second = shift; + + return Future->done([$first, $second]); + }); + }); +} +``` + +--- +class: ex-asyncawait + +## With async and await + +```perl +use Future::AsyncAwait; + +async sub do_two_things +{ + my $first = await do_first_thing(); + + my $second = await do_second_thing($first); + + return [$first, $second]; +} +``` + +??? +There are caveats: Localized variable assignments don't work, nor anything that has implied local-like behavior. +--- + +## Events in the world + + + --- class: center, middle name: conclusion