]> Dogcows Code - chaz/talk-event-driven-programming-in-perl/blob - slides.html
add reactor graph and asyncawait slides
[chaz/talk-event-driven-programming-in-perl] / slides.html
1 <!DOCTYPE html>
2 <html><head><meta charset="utf-8"><title>Event-driven Programming in Perl</title><link rel="stylesheet" href="css/common.css"><link rel="stylesheet" href="css/slides.css"></head><body><textarea id="source">
3
4 class: center, middle
5 name: title
6
7 # Event-driven Programming in Perl
8
9 Charles McGarvey
10
11 ???
12 - Hi. I'm Charles McGarvey.
13 - Been a Perl programmer for a long time...
14
15 ---
16 class: center, middle
17 name: bluehost
18
19 ???
20 - My employer is hiring.
21 - It's a pretty cool employer...
22
23 ---
24 ## "Normal" [userspace] programs
25
26 .big[
27 1. Parse args.
28 2. Read input.
29 3. Do stuff.
30 4. Write results as output.
31 ]
32
33 ---
34 class: pizza
35 background-image: url(img/pizza.jpg)
36 background-size: 100%
37
38 --
39 ```bash
40 # orderpizza --crust-type=thin \
41 --toppings=cheese,pepperoni,mushrooms
42 ```
43
44 --
45 ```perl
46 # source code of the orderpizza program
47
48 my $order = get_order_from_args(@ARGV);
49
50 my $ingredients = gather_ingredients($order);
51
52 my $pizza = prepare_and_bake($order, $ingredentials);
53
54 print($pizza);
55 ```
56
57 ???
58 But some programs are long-lived.
59
60 ---
61 ## Event-driven programs
62
63 .big[
64 1. Events happen.
65 2. When events happen, some code runs and does something.
66 ]
67
68 ???
69 At it's core, event-driven programming is this simple.
70
71 But there are some complications and things to knows, which is why this talk exists.
72
73 ---
74 name: graph-eventloop
75 class: center, middle
76
77 ## Event loop
78
79 ![Event loop](img/eventloop.svg)
80
81 ???
82 We'll refine this model as we go.
83
84 ---
85 class: ex-hwinterrupts
86
87 ## Hardware interrupts
88
89 ```bash
90 # cat /proc/interrupts
91 CPU0 CPU1
92 0: 51 0 IR-IO-APIC 2-edge timer
93 1: 685006 5 IR-IO-APIC 1-edge i8042
94 8: 0 0 IR-IO-APIC 8-edge rtc0
95 9: 1724419 6314 IR-IO-APIC 9-fasteoi acpi
96 12: 12300601 138 IR-IO-APIC 12-edge i8042
97 16: 0 0 IR-IO-APIC 16-fasteoi i801_smbus
98 120: 0 0 DMAR-MSI 0-edge dmar0
99 121: 0 0 DMAR-MSI 1-edge dmar1
100 122: 7009890 45112 IR-PCI-MSI 327680-edge xhci_hcd
101 123: 44 3 IR-PCI-MSI 360448-edge mei_me
102 124: 509 0 IR-PCI-MSI 1048576-edge rtsx_pci
103 125: 80130 0 IR-PCI-MSI 2621440-edge nvme0q0, nvme0q1
104 126: 121892439 2961357 IR-PCI-MSI 32768-edge i915
105 127: 49 100 IR-PCI-MSI 514048-edge snd_hda_intel:card0
106 128: 0 79412 IR-PCI-MSI 2621441-edge nvme0q2
107
108 ...
109 ```
110
111 ???
112 When a HW interrupt happens, the appropriate code to run is locate in the interrupt service routine
113
114 ---
115 class: ex-pressenter
116
117 ## Your first event-driven program
118
119 .middle[
120 ```perl
121 print "Press <Enter> to continue.";
122 <STDIN>;
123
124 handle_enter_keypress_event();
125 ```
126 ]
127
128 ---
129 class: ex-pressenter
130
131 ## Your first event-driven program
132
133 .middle[
134 ```perl
135 print "Press <Enter> to continue.";
136 *<STDIN>;
137
138 handle_enter_keypress_event();
139 ```
140 ]
141
142 .big[
143 - Wait for an event
144 ]
145
146 ---
147 class: ex-pressenter
148
149 ## Your first event-driven program
150
151 .middle[
152 ```perl
153 print "Press <Enter> to continue.";
154 *<STDIN>;
155
156 handle_enter_keypress_event();
157 ```
158 ]
159
160 .big[
161 - Wait for an event
162 - Event source
163 ]
164
165 ---
166 class: ex-pressenter
167
168 ## Your first event-driven program
169
170 .middle[
171 ```perl
172 print "Press <Enter> to continue.";
173 <STDIN>;
174
175 *handle_enter_keypress_event();
176 ```
177 ]
178
179 .big[
180 - Wait for an event
181 - Event source
182 - Event handler
183 ]
184
185 ---
186 class: ex-signals
187
188 ## Signals
189
190 ```perl
191 use POSIX;
192
193 $SIG{USR1} = sub { handle_usr1_signal_event() };
194 $SIG{ALRM} = sub { handle_timer_event() };
195 $SIG{QUIT} = sub { exit() };
196
197 alarm(3);
198
199 while (1) { POSIX::pause() }
200 ```
201
202 ---
203 class: ex-signals
204
205 ## Signals
206
207 ```perl
208 use POSIX;
209
210 *$SIG{USR1} = sub { handle_usr1_signal_event() };
211 *$SIG{ALRM} = sub { handle_timer_event() };
212 *$SIG{QUIT} = sub { exit() };
213
214 alarm(3);
215
216 while (1) { POSIX::pause() }
217 ```
218
219 ???
220 Notice that this program is capable of handling more than just one event handler at a time.
221
222 ---
223 class: ex-signals
224
225 ## Signals
226
227 ```perl
228 use POSIX;
229
230 $SIG{USR1} = sub { handle_usr1_signal_event() };
231 $SIG{ALRM} = sub { handle_timer_event() };
232 $SIG{QUIT} = sub { exit() };
233
234 alarm(3);
235
236 *while (1) { POSIX::pause() }
237 ```
238
239 .big[
240 - Program yields time to the kernel
241 ]
242
243 ???
244 This example has a loop, but it's not really doing anything.
245
246 But actually it is doing something very important: It's yielding its processing time to the kernel.
247
248 And kernel informs the program of events.
249
250 You might be able to use `sleep` as well, but some implementations of libc
251 in the past have implemented `sleep` using `alarm`.
252
253 Don't know how common that is nowadays, but old habbits...
254
255 ---
256 class: ex-gui
257
258 ## Graphical user interface example
259
260 ```perl
261 use Gtk3 '-init';
262
263 my $window = Gtk3::Window->new;
264
265 $window->signal_connect('key-press-event' => \&handle_keypress_event);
266 $window->signal_connect('delete-event' => \&Gtk3::main_quit);
267
268 $window->show_all;
269
270 Gtk3::main();
271 ```
272
273 ???
274 A user interface happens to be a good place to use evented code because humans are spontaneous and unpredictable.
275
276 ---
277 class: ex-gui
278
279 ## Graphical user interface example
280
281 ```perl
282 use Gtk3 '-init';
283
284 my $window = Gtk3::Window->new;
285
286 *$window->signal_connect('key-press-event' => \&handle_keypress_event);
287 *$window->signal_connect('delete-event' => \&Gtk3::main_quit);
288
289 $window->show_all;
290
291 Gtk3::main();
292 ```
293
294 .big[
295 - Event handlers
296 ]
297
298 ---
299 class: ex-gui
300
301 ## Graphical user interface example
302
303 ```perl
304 use Gtk3 '-init';
305
306 my $window = Gtk3::Window->new;
307
308 $window->signal_connect('key-press-event' => \&handle_keypress_event);
309 $window->signal_connect('delete-event' => \&Gtk3::main_quit);
310
311 $window->show_all;
312
313 *Gtk3::main();
314 ```
315
316 .big[
317 - Event handlers
318 - Yield and wait for events
319 ]
320
321 ---
322 class: event-types
323
324 ## Types of events
325
326 - IO
327
328 ???
329 Data available on a socket, or a new connection.
330
331 Server or client, data across a wire cannot typically be relied upon to arrive in a predictable fashion, so an
332 event-driven architect makes a lot of sense for network applications.
333
334 --
335 - Signals
336
337 ???
338 As far as my program is concerned, it can receive a signal or message from another program at any time.
339
340 --
341 - Timer
342
343 ???
344 If I need something to happen to happen in five minutes or at a specific absolute time, using the idea of an alarm clock
345 is tempting. I can set an alarm and pretend that the clock itself is a source of events.
346
347 --
348 - User input
349
350 ???
351 Human beings of course are masters of spontaneity.
352
353 Are they going to press a button on the keyboard next, or move the mouse? If my program is connected to a microphone,
354 maybe the human is going to start talking to the program. The program has to be ready for anything, so defining and
355 accepting "events" for all the different ways that a human can interact with the program is a good way to go.
356
357 --
358 - Anything that can happen spontaneously in the real world.
359
360 ???
361 Lots of other external systems (besides humans) can "generate" events.
362
363 Lot of this requires kernel facilities. Speaking of which, how are these types of things implemented?
364
365 ---
366 class: syscalls
367
368 ## How event-driven userspace code works
369
370 ### syscalls
371
372 - [`pause`](http://man.he.net/man2/pause) - Sleeps until signal
373
374 --
375 - [`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
376
377 --
378 - [`clock_gettime`](http://man.he.net/man2/clock_gettime) - What time is it now?
379
380 ---
381
382 ## Reactor pattern
383
384 .big[
385 - Queues events asynchronously.
386 - Demultiplexes and dispatches synchronously.
387 ]
388
389 ---
390 name: graph-reactor
391 class: center, middle
392
393 ## Reactor pattern
394
395 ![Reactor](img/reactor.svg)
396
397 ---
398 class: ex-basicreactor
399
400 ## The basic reactor
401
402 ```perl
403 our $timers = [...];
404 our $io_handles = [...];
405
406 while (1) {
407 my $next_timer = find_next_timer($timers);
408
409 poll($io_handles, $next_timer->time_from_now);
410
411 handle_ready_io_handles($io_handles);
412 handle_expired_timers($timers);
413 }
414 ```
415
416 ---
417 class: ex-basicreactor
418
419 ## The basic reactor
420
421 ```perl
422 our $timers = [...];
423 our $io_handles = [...];
424
425 while (1) {
426 my $next_timer = find_next_timer($timers);
427
428 * poll($io_handles, $next_timer->time_from_now);
429
430 handle_ready_io_handles($io_handles);
431 handle_expired_timers($timers);
432 }
433 ```
434
435 ---
436
437 ## Reactor examples on CPAN
438
439 .big[
440 - [`POE::Loop::IO_Poll`](https://metacpan.org/source/POE::Loop::IO_Poll)
441 - [`POE::Loop::Select`](https://metacpan.org/source/POE::Loop::Select)
442 - [`AnyEvent::Loop`](https://metacpan.org/source/AnyEvent::Loop)
443 - [`IO::Async::Loop::Poll`](https://metacpan.org/source/IO::Async::Loop::Poll)
444 - [`IO::Async::Loop::Select`](https://metacpan.org/source/IO::Async::Loop::Select)
445 - [`Mojo::Reactor::Poll`](https://metacpan.org/source/Mojo::Reactor::Poll)
446 ]
447
448 ---
449 class: center, middle
450
451 ## Use [`Future::AsyncAwait`](https://metacpan.org/pod/Future::AsyncAwait).
452
453 ???
454 If you have used JavaScript recently, you may have used its "async/await" feature to clean up your non-blocking code.
455
456 ---
457 class: center, middle
458
459 ### Yes, Perl can do it, too!
460
461 ---
462 class: ex-asyncawait
463
464 ## Without async and await
465
466 ```perl
467 use Future;
468
469 sub do_two_things {
470 return do_first_thing()->then(sub {
471 my $first = shift;
472
473 return do_second_thing($first)->then(sub {
474 my $second = shift;
475
476 return Future->done([$first, $second]);
477 });
478 });
479 }
480 ```
481
482 ---
483 class: ex-asyncawait
484
485 ## With async and await
486
487 ```perl
488 use Future::AsyncAwait;
489
490 async sub do_two_things
491 {
492 my $first = await do_first_thing();
493
494 my $second = await do_second_thing($first);
495
496 return [$first, $second];
497 }
498 ```
499
500 ???
501 There are caveats: Localized variable assignments don't work, nor anything that has implied local-like behavior.
502 ---
503
504 ## Events in the world
505
506
507
508 ---
509 class: center, middle
510 name: conclusion
511
512 ## Conclusion:
513
514 ### Perl is fun.
515
516 ---
517 class: center, middle
518 name: last
519
520 ### Thanks.
521
522 </textarea><script src="https://gnab.github.io/remark/downloads/remark-latest.min.js"></script><script>var slideshow = remark.create({countIncrementalSlides: true, highlightLanguage: '', highlightLines: true, highlightStyle: 'hybrid', ratio: '16:9', /*slideNumberFormat: '',*/ navigation: {scroll: false, touch: false, click: false}})</script><script src="js/common.js"></script><script src="js/slides.js"></script></body></html>
523 <!-- vim: set ts=4 sts=4 sw=4 tw=120 et ft=markdown nowrap: -->
This page took 0.064679 seconds and 4 git commands to generate.