From afb7de1b61d2bf725c70e8f6be00592f1b762e82 Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Mon, 18 Jun 2018 00:48:44 -0600 Subject: [PATCH] add more slides on Future --- css/slides.css | 11 +++ notes.txt | 23 ++--- slides.html | 246 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 266 insertions(+), 14 deletions(-) diff --git a/css/slides.css b/css/slides.css index eb366c3..accda71 100644 --- a/css/slides.css +++ b/css/slides.css @@ -71,4 +71,15 @@ font-size: 38px; } +.ex-debugging .bash { + font-size: 38px; +} + +.ex-future .perl { + font-size: 32px; +} + +.ex-future2 .perl { + font-size: 24px; +} diff --git a/notes.txt b/notes.txt index 6b732a6..8a43724 100644 --- a/notes.txt +++ b/notes.txt @@ -13,18 +13,19 @@ X User input X Signal X Anything that can spontaneously happen in the real world. -3. How to write a modern event-loop. +3. How to write a modern event-loop (reactor style). X kernel facilities (poll, select, etc.) -4. List of already-built event loops. -- EV -- Glib +4. List of already-built reactors. +X EV +X Glib +X ... 5. Event-driven programming in Perl -- POE - AnyEvent - IO::Async - Mojo::IOLoop +- POE 6. Special considerations X Exceptions in event-driven code. @@ -33,9 +34,9 @@ X SIGPIPE, EPIPE - might have more to do with long-lived processes rather than X You should almost always check the return code of your syscalls to see if they succeeded or not. 7. Promises: -- Future -- Future::AsyncAwait -- Future::Utils +X Future +X Future::AsyncAwait +X Future::Utils 8. Real-world uses for event-driven applications: - Webhooks @@ -51,13 +52,13 @@ X What is event-driven programming? demultiplex them, delivering them to appropriate handlers. - C10k problem - EDA (event-driven architecture) -- Benefits of Event-driven -- How to debug event-driven code. +X Benefits of Event-driven +X How to debug event-driven code. Traditional programs: - CGI - web server calls your program, and your program does its thing and finishes. -- filters - grep, less, sed, etc. Like a function, the program takes its input +X filters - grep, less, sed, etc. Like a function, the program takes its input and produces some output. Perl features: diff --git a/slides.html b/slides.html index 8904bd2..161851a 100644 --- a/slides.html +++ b/slides.html @@ -464,7 +464,6 @@ while (1) { ``` --- - ## Reactor examples on CPAN .big[ @@ -480,6 +479,64 @@ while (1) { These links, which will be available to you with the slides, link directly to the source code of these modules on metacpan so you can take a look at how they work. +--- +## Reactors + +.col.big[ +- [`Cocoa::EventLoop`](https://metacpan.org/pod/Cocoa::EventLoop) +- [`EV`](https://metacpan.org/pod/EV) +- [`Event::Lib`](https://metacpan.org/pod/Event::Lib) +- [`Event`](https://metacpan.org/pod/Event) +- [`FLTK`](https://metacpan.org/pod/FLTK) +] +.col.big[ +- [`Glib`](https://metacpan.org/pod/Glib), [`Gtk`](https://metacpan.org/pod/Gtk), [`Gtk2`](https://metacpan.org/pod/Gtk2) +- [`Tk`](https://metacpan.org/pod/Tk) +- [`UV`](https://metacpan.org/pod/UV) +- [`Wx`](https://metacpan.org/pod/Wx) +- probably more... +] + +??? +I'm not going to go over any of these. + +- You can use any one of these directly. +- Some of that are better than others (obvious). +- Which one you choose may depend one what you're building. + - If you're building a GUI, your choice is made for you. + - High-concurrency network application, `EV` is a good choice. + +But actually you may not need to pick one... + +--- +class: center, middle + +## Reactor "front ends" + +??? +By my count there are four main front ends. + +--- +## Reactor "front ends" + +.big[ +- [**`POE`**](https://metacpan.org/pod/POE) - Portable multitasking and networking framework for any event loop (or Perl, Objects, and Events) +- [**`IO::Async`**](https://metacpan.org/pod/IO::Async) - Asynchronous event-driven programming +- [**`Mojo::IOLoop`**](https://metacpan.org/pod/Mojo::IOLoop) - Minimalistic event loop +- [**`AnyEvent`**](https://metacpan.org/pod/AnyEvent) - The DBI of event loop programming +] + +??? +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. + +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. + --- name: not-all-roses class: center, middle @@ -530,6 +587,9 @@ $promise->on_done(sub { ... }); $promise->on_fail(sub { ... }); ``` +??? +More on this later. + --- class: center, middle @@ -566,7 +626,152 @@ Look for `EPIPE` from syscalls (like [`write`](http://man.he.net/man2/write)) in --- class: center, middle -## Use [`Future::AsyncAwait`](https://metacpan.org/pod/Future::AsyncAwait). +## Debugging event-driven code + +--- +class: ex-debugging + +## Debugging event-driven code + +.big[ +- Print debug info to `STDERR`. +] + +```bash +export PERL_FUTURE_DEBUG=1 +# and +export ANYEVENT_DEBUG=8 +# or +export MOJO_IOLOOP_DEBUG=1 +# etc. +``` + +--- +## Debugging event-driven code + +.big[ +- Print debug info to `STDERR`. +- Check out [`AnyEvent::Debug`](https://metacpan.org/pod/AnyEvent::Debug). +] + +--- +## Debugging event-driven code + +.big[ +- Print debug info to `STDERR`. +- Check out [`AnyEvent::Debug`](https://metacpan.org/pod/AnyEvent::Debug). +- Use [`perl5db.pl`](https://metacpan.org/pod/perl5db.pl) and other `Devel::` debuggers. +] + +??? +Traditional debuggers are still useful for event-driven code. +- Be sure to carefully avoid memory leaks -- they are more devastating in long-lived programs which event-driven +programs tend to be. + +--- +class: center, middle + +## Promises: +### Proxy objects for future values + +??? +Proxy objects for values that have not yet been retrieved or computed. + +- In some cases, promises can provide you an alternative, often more useful interface to callbacks. + +--- +class: ex-future + +## Basic usage (using [`Future`](https://metacpan.org/pod/Future)) + +```perl +my $future = fetch_remote_file($url); + +$future->on_done(sub($filename, $contents) { + print "Fetched $filename\n"; +}); +``` + +??? +The future is an object that stands in for the thing we actually want until the thing we want is available. + +-- +```perl +$future->on_fail(sub($error) { + warn $error; +}); +``` + +??? +If the operation that provides the `Future` isn't able to fulfill its promise to provide us what we want, the `Future` +may be set to a "fail" state. + +- For any operation that can fail (and that includes almost everything), it's a good idea to handle errors. + +--- +class: ex-future + +## Chaining futures + +```perl +my $future = fetch_remote_file($url) + ->then(sub($filename, $contents) { + my $another_future = write_local_file("/tmp/$filename", + $contents); + return $another_future; + }); + +$future->on_done(sub($filepath) { + print "Saved file to $filepath\n"; +}); + +$future->on_fail(sub($error) { + warn $error; +}); +``` + +--- +class: ex-future2 + +## Creating futures + +```perl +use AnyEvent::HTTP; +use Future; + +sub fetch_remote_file($url) { + my $future = Future->new; + + http_get $url => sub($data, $headers) { + if ($headers->{Status} =~ /^[23]/) { + my ($filename) = get_filename($headers); + $future->done($filename, $data); + } + else { + $future->fail("Failed to fetch file: $headers->{Reason}"); + } + }; + + return $future; +} +``` + +--- +class: center, middle + +Check out [Paul Evan's blog](http://leonerds-code.blogspot.com/2013/12/futures-advent-day-1.html) for more things you can do with `Future`s. + +And, of course, [read the pod](https://metacpan.org/pod/Future). + +??? +Paul did an advent calendar with short posts detailing the things you can do with `Future`. + +- It's really well done. + +--- +class: center, middle + +## There's also [`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. @@ -617,11 +822,46 @@ async sub do_two_things ??? There are caveats: Localized variable assignments don't work, nor anything that has implied local-like behavior. + --- +class: center, middle -## Events in the world +## Finally, there's also [`Future::Utils`](https://metacpan.org/pod/Future::Utils). + +--- +class: ex-future2 +## Call +```perl +my $future = call { + do_stuff(); + + ... + + my $future = ...; + return $future; +}; +``` + +Any exceptions throw in the code block are caught and become a failed `Future`. + +--- +class: ex-future2 + +## Loops and stuff + +```perl +use Future::Utils qw(repeat); + +my $eventual_future = repeat { + my $trial_future = ... + return $trial_future; +} while => sub($last_trial_future) { return should_keep_going($last_trial_future) }; +``` + +--- +## Events in the world --- class: center, middle -- 2.45.2