From: Charles McGarvey Date: Sun, 17 Jun 2018 20:55:09 +0000 (-0600) Subject: add reactor graph and asyncawait slides X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=55d3713208b2267dfbb669f76a9a21f4ff6092d5;p=chaz%2Ftalk-event-driven-programming-in-perl add reactor graph and asyncawait slides --- diff --git a/.gitignore b/.gitignore index b0b0f73..2d60b80 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.pdf /img/eventloop.svg +/img/reactor.svg /remark.min.js /slides-offline.html diff --git a/css/slides.css b/css/slides.css index 36ce1a2..93fa174 100644 --- a/css/slides.css +++ b/css/slides.css @@ -3,6 +3,14 @@ background: url('../img/bluehost.png') 1100px; } +#slide-graph-eventloop img { + width: 100%; +} +#slide-graph-reactor img { + width: 100%; +} + + .pizza img { width: 70%; } @@ -41,3 +49,7 @@ font-size: 38px; } +.ex-asyncawait .perl { + font-size: 32px; +} + diff --git a/img/eventloop.dot b/img/eventloop.dot index 3c0c3b3..e8a8cbe 100644 --- a/img/eventloop.dot +++ b/img/eventloop.dot @@ -22,7 +22,7 @@ digraph G { "Event source 1" -> "Wait for\nan event\nto happen" "Event source 2" -> "Wait for\nan event\nto happen" - "Event source n" -> "Wait for\nan event\nto happen" + "Event source N" -> "Wait for\nan event\nto happen" "Wait for\nan event\nto happen" -> "Handle an\nevent" [label="Something happened...\n", tailport="n", headport="n"] "Handle an\nevent" -> "Wait for\nan event\nto happen" [tailport="s", headport="s"] diff --git a/img/reactor.dot b/img/reactor.dot new file mode 100644 index 0000000..284b606 --- /dev/null +++ b/img/reactor.dot @@ -0,0 +1,37 @@ + +digraph G { + rankdir = LR + + node + [ + fontname = "Inconsolata" + fontsize = 20 + shape = record + style = rounded + margin = "0.2,0.2" + ] + + edge + [ + fontname = "Inconsolata" + fontsize = 18 + arrowhead = vee + arrowtail = vee + arrowsize = 2 + ] + + "Event source 1" -> "Wait for\nan event\nto happen" + "Event source 2" -> "Wait for\nan event\nto happen" + "Event source N" -> "Wait for\nan event\nto happen" + + "Wait for\nan event\nto happen" -> "Demultiplex and\ndispatch events" [tailport="n", headport="n"] + "Demultiplex and\ndispatch events" -> "Wait for\nan event\nto happen" [tailport="s", headport="s"] + + "Demultiplex and\ndispatch events" -> "Event handler 1" + "Demultiplex and\ndispatch events" -> "Event handler 2" + "Demultiplex and\ndispatch events" -> "Event handler M" + + + "Demultiplex and\ndispatch events" [style="rounded,filled",fillcolor="#FFFF88"] +} + diff --git a/js/slides.js b/js/slides.js index e69de29..078d194 100644 --- a/js/slides.js +++ b/js/slides.js @@ -0,0 +1 @@ +createHotkey(1, 'graph-eventloop'); diff --git a/slides.html b/slides.html index 9eae800..d86ee03 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,66 @@ while (1) { - [`Mojo::Reactor::Poll`](https://metacpan.org/source/Mojo::Reactor::Poll) ] +--- +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