From: Charles McGarvey Date: Sun, 17 Jun 2018 20:01:40 +0000 (-0600) Subject: add more sections X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftalk-event-driven-programming-in-perl;a=commitdiff_plain;h=1e5589cbb1518565f28a66bafd4882eec1d9acd5 add more sections --- diff --git a/.gitignore b/.gitignore index 5429412..b0b0f73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ +*.pdf +/img/eventloop.svg /remark.min.js /slides-offline.html diff --git a/Makefile b/Makefile index 272b370..2af1c47 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ run-offline: offline $(DOT) -Tsvg -o$@ $< $(SLIDES).pdf: slides.html $(wildcard css/*) $(wildcard img/*) $(svgfiles) - docker run --rm -v `pwd`:/pwd astefanutti/decktape /pwd/slides.html /pwd/$(SLIDES).pdf + docker run --network host --rm -t -v `pwd`:/slides astefanutti/decktape http://localhost:5000 /slides/$(SLIDES).pdf slides-offline.html: slides.html sed -e '1 a ' \ diff --git a/abstract.txt b/abstract.txt index f106536..af6e885 100644 --- a/abstract.txt +++ b/abstract.txt @@ -1,7 +1,7 @@ Event-driven programming in Perl Charles McGarvey | Mon, 6/18 at 2:00 pm | 50 minutes | Ballroom B -Event-driven programming is a paradigm where programmers creates subroutines +Event-driven programming is a paradigm where programmers create subroutines that get called when events occur. Events can be just about anything: timers expiring, new data becoming available to read from a socket, even humans clicking on things in an interactive program. diff --git a/app.psgi b/app.psgi new file mode 100644 index 0000000..006ed67 --- /dev/null +++ b/app.psgi @@ -0,0 +1,15 @@ +#!/usr/bin/env perl + +use Plack::App::Directory; +use Plack::App::File; +use Plack::Builder; +use Plack::Util; + +builder { + mount '/css' => Plack::App::Directory->new(root => 'css')->to_app; + mount '/img' => Plack::App::Directory->new(root => 'img')->to_app; + mount '/js' => Plack::App::Directory->new(root => 'js')->to_app; + mount '/remark.min.js' => Plack::App::File->new(file => 'remark.min.js')->to_app; + mount '/' => Plack::App::File->new(file => 'slides-offline.html')->to_app; +}; + diff --git a/css/common.css b/css/common.css index 5fe4e74..525370d 100644 --- a/css/common.css +++ b/css/common.css @@ -91,3 +91,14 @@ color: #7d9726; } +.big { + font-size: 150%; +} + +.remark-code-line-highlighted { + background-color: rgba(200,200,255,.25); +} +.hljs-hybrid .hljs { + background: rgba(29,31,33,.96); +} + diff --git a/css/slides.css b/css/slides.css index 04d938b..36ce1a2 100644 --- a/css/slides.css +++ b/css/slides.css @@ -1,5 +1,43 @@ -#slide-bluehost img { - width: 250px; +#slide-bluehost { + background: url('../img/bluehost.png') 1100px; +} + +.pizza img { + width: 70%; +} +.pizza .bash { + font-size: 38px; +} +.pizza .perl { + font-size: 36px; +} + +.ex-hwinterrupts .bash { + font-size: 22px; +} + +.ex-pressenter .perl { + font-size: 40px; +} + +.ex-signals .perl { + font-size: 36px; +} + +.ex-gui .perl { + font-size: 28px; +} + +.event-types ul { + font-size: 34px; +} + +.syscalls ul { + font-size: 34px; +} + +.ex-basicreactor .perl { + font-size: 38px; } diff --git a/img/bluehost.png b/img/bluehost.png index 3a83180..3d124df 100644 Binary files a/img/bluehost.png and b/img/bluehost.png differ diff --git a/img/eventloop.dot b/img/eventloop.dot new file mode 100644 index 0000000..3c0c3b3 --- /dev/null +++ b/img/eventloop.dot @@ -0,0 +1,30 @@ + +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" -> "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/pizza.jpg b/img/pizza.jpg new file mode 100644 index 0000000..f92a76d Binary files /dev/null and b/img/pizza.jpg differ diff --git a/notes.txt b/notes.txt index 6841507..16f2f5c 100644 --- a/notes.txt +++ b/notes.txt @@ -1,40 +1,66 @@ Topics: -Evolution of event-driven programming: -- Wait for a key press or line of text. -- Interrupts (hardware and software). -- Modern event loops +1. Evolution of event-driven programming: +X Wait for a key press or line of text. +X Interrupts (hardware and software). +X Modern event loops -How to write a modern event-loop. -- kernel facilities (poll, select, etc.) +2. Types of events in modern applications: +X IO +X Timer +X User input +X Signal +X Anything that can spontaneously happen in the real world. -Event-drive programming in Perl -- POE -- AnyEvent -- IO::Async +3. How to write a modern event-loop. +X kernel facilities (poll, select, etc.) -List of already-built event loops. +4. List of already-built event loops. - EV - Glib -Types of events in modern applications: -- Data available -- Timer -- User input -- Signal -- Anything that can spontaneously happen in the real world. +5. Event-driven programming in Perl +- POE +- AnyEvent +- IO::Async +- Mojo::IOLoop -Exceptions in event-driven code. +6. Special considerations +- Exceptions in event-driven code. +- SIGPIPE, EPIPE - might have more to do with long-lived processes rather than + just event-driven programming, but still something to watch out for... -Promises: +7. Promises: - Future - Future::AsyncAwait - Future::Utils -Real-world uses for event-driven applications: +8. Real-world uses for event-driven applications: - Webhooks -- WebSockets - PubsubHubbub - msg queue + + + +Other topics: +X What is event-driven programming? +- Reactor: event loop that can receive multiple types of events and + demultiplex them, delivering them to appropriate handlers. +- C10k problem +- EDA (event-driven architecture) +- Benefits of Event-driven + +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 + and produces some output. + +Perl features: +- first-class subroutines + +- Can mix traditional architecture with event-driven (like docker that + provides both an http and command-line interface. + diff --git a/slides.html b/slides.html index 46dbe40..9eae800 100644 --- a/slides.html +++ b/slides.html @@ -16,14 +16,389 @@ Charles McGarvey class: center, middle name: bluehost -![Bluehost](img/bluehost.png) - -### https://bluehost.com/jobs - ??? - My employer is hiring. - It's a pretty cool employer... +--- +## "Normal" [userspace] programs + +.big[ +1. Parse args. +2. Read input. +3. Do stuff. +4. Write results as output. +] + +--- +class: pizza +background-image: url(img/pizza.jpg) +background-size: 100% + +-- +```bash +# orderpizza --crust-type=thin \ + --toppings=cheese,pepperoni,mushrooms +``` + +-- +```perl +# source code of the orderpizza program + +my $order = get_order_from_args(@ARGV); + +my $ingredients = gather_ingredients($order); + +my $pizza = prepare_and_bake($order, $ingredentials); + +print($pizza); +``` + +--- +## Event-driven programs + +.big[ +1. Events happen. +2. When events happen, some code runs and does something. +] + +??? +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. + +--- +class: center, middle + +![Event loop](img/eventloop.svg) + +??? +We'll refine this model as we go. + +--- +class: ex-hwinterrupts + +## Hardware interrupts + +```bash +# cat /proc/interrupts + CPU0 CPU1 + 0: 51 0 IR-IO-APIC 2-edge timer + 1: 685006 5 IR-IO-APIC 1-edge i8042 + 8: 0 0 IR-IO-APIC 8-edge rtc0 + 9: 1724419 6314 IR-IO-APIC 9-fasteoi acpi + 12: 12300601 138 IR-IO-APIC 12-edge i8042 + 16: 0 0 IR-IO-APIC 16-fasteoi i801_smbus + 120: 0 0 DMAR-MSI 0-edge dmar0 + 121: 0 0 DMAR-MSI 1-edge dmar1 + 122: 7009890 45112 IR-PCI-MSI 327680-edge xhci_hcd + 123: 44 3 IR-PCI-MSI 360448-edge mei_me + 124: 509 0 IR-PCI-MSI 1048576-edge rtsx_pci + 125: 80130 0 IR-PCI-MSI 2621440-edge nvme0q0, nvme0q1 + 126: 121892439 2961357 IR-PCI-MSI 32768-edge i915 + 127: 49 100 IR-PCI-MSI 514048-edge snd_hda_intel:card0 + 128: 0 79412 IR-PCI-MSI 2621441-edge nvme0q2 + +... +``` + +??? +When a HW interrupt happens, the appropriate code to run is locate in the interrupt service routine + +--- +class: ex-pressenter + +## Your first event-driven program + +.middle[ +```perl +print "Press to continue."; +; + +handle_enter_keypress_event(); +``` +] + +--- +class: ex-pressenter + +## Your first event-driven program + +.middle[ +```perl +print "Press to continue."; +*; + +handle_enter_keypress_event(); +``` +] + +.big[ +- Wait for an event +] + +--- +class: ex-pressenter + +## Your first event-driven program + +.middle[ +```perl +print "Press to continue."; +*; + +handle_enter_keypress_event(); +``` +] + +.big[ +- Wait for an event +- Event source +] + +--- +class: ex-pressenter + +## Your first event-driven program + +.middle[ +```perl +print "Press to continue."; +; + +*handle_enter_keypress_event(); +``` +] + +.big[ +- Wait for an event +- Event source +- Event handler +] + +--- +class: ex-signals + +## Signals + +```perl +use POSIX; + +$SIG{USR1} = sub { handle_usr1_signal_event() }; +$SIG{ALRM} = sub { handle_timer_event() }; +$SIG{QUIT} = sub { exit() }; + +alarm(3); + +while (1) { POSIX::pause() } +``` + +--- +class: ex-signals + +## Signals + +```perl +use POSIX; + +*$SIG{USR1} = sub { handle_usr1_signal_event() }; +*$SIG{ALRM} = sub { handle_timer_event() }; +*$SIG{QUIT} = sub { exit() }; + +alarm(3); + +while (1) { POSIX::pause() } +``` + +??? +Notice that this program is capable of handling more than just one event handler at a time. + +--- +class: ex-signals + +## Signals + +```perl +use POSIX; + +$SIG{USR1} = sub { handle_usr1_signal_event() }; +$SIG{ALRM} = sub { handle_timer_event() }; +$SIG{QUIT} = sub { exit() }; + +alarm(3); + +*while (1) { POSIX::pause() } +``` + +.big[ +- Program yields time to the kernel +] + +??? +This example has a loop, but it's not really doing anything. + +But actually it is doing something very important: It's yielding its processing time to the kernel. + +And kernel informs the program of events. + +You might be able to use `sleep` as well, but some implementations of libc +in the past have implemented `sleep` using `alarm`. + +Don't know how common that is nowadays, but old habbits... + +--- +class: ex-gui + +## Graphical user interface example + +```perl +use Gtk3 '-init'; + +my $window = Gtk3::Window->new; + +$window->signal_connect('key-press-event' => \&handle_keypress_event); +$window->signal_connect('delete-event' => \&Gtk3::main_quit); + +$window->show_all; + +Gtk3::main(); +``` + +??? +A user interface happens to be a good place to use evented code because humans are spontaneous and unpredictable. + +--- +class: ex-gui + +## Graphical user interface example + +```perl +use Gtk3 '-init'; + +my $window = Gtk3::Window->new; + +*$window->signal_connect('key-press-event' => \&handle_keypress_event); +*$window->signal_connect('delete-event' => \&Gtk3::main_quit); + +$window->show_all; + +Gtk3::main(); +``` + +.big[ +- Event handlers +] + +--- +class: ex-gui + +## Graphical user interface example + +```perl +use Gtk3 '-init'; + +my $window = Gtk3::Window->new; + +$window->signal_connect('key-press-event' => \&handle_keypress_event); +$window->signal_connect('delete-event' => \&Gtk3::main_quit); + +$window->show_all; + +*Gtk3::main(); +``` + +.big[ +- Event handlers +- Yield and wait for events +] + +--- +class: event-types + +## Types of events + +- IO + +??? +Data available on a socket, or a new connection. + +Server or client, data across a wire cannot typically be relied upon to arrive in a predictable fashion, so an +event-driven architect makes a lot of sense for network applications. + +-- +- Signals + +??? +As far as my program is concerned, it can receive a signal or message from another program at any time. + +-- +- Timer + +??? +If I need something to happen to happen in five minutes or at a specific absolute time, using the idea of an alarm clock +is tempting. I can set an alarm and pretend that the clock itself is a source of events. + +-- +- User input + +??? +Human beings of course are masters of spontaneity. + +Are they going to press a button on the keyboard next, or move the mouse? If my program is connected to a microphone, +maybe the human is going to start talking to the program. The program has to be ready for anything, so defining and +accepting "events" for all the different ways that a human can interact with the program is a good way to go. + +-- +- Anything that can happen spontaneously in the real world. + +??? +Lots of other external systems (besides humans) can "generate" events. + +Lot of this requires kernel facilities. Speaking of which, how are these types of things implemented? + +--- +class: syscalls + +## How event-driven userspace code works + +### 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? + +--- +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 + +.big[ +- [`POE::Loop::IO_Poll`](https://metacpan.org/source/POE::Loop::IO_Poll) +- [`POE::Loop::Select`](https://metacpan.org/source/POE::Loop::Select) +- [`AnyEvent::Loop`](https://metacpan.org/source/AnyEvent::Loop) +- [`IO::Async::Loop::Poll`](https://metacpan.org/source/IO::Async::Loop::Poll) +- [`IO::Async::Loop::Select`](https://metacpan.org/source/IO::Async::Loop::Select) +- [`Mojo::Reactor::Poll`](https://metacpan.org/source/Mojo::Reactor::Poll) +] + --- class: center, middle name: conclusion @@ -38,5 +413,5 @@ name: last ### Thanks. - +