Slide 1

Slide 1 text

Asynchronous Programing Fundamentals Samantha Quiñones

Slide 2

Slide 2 text

Samantha Quiñones Principal Software Engineer Code and Community Champion AOL Inc. @ieatkillerbees @squinones ɂ http://squinones.github.io ɔ https://joind.in/talk/3a1de

Slide 3

Slide 3 text

Synchronous Operations

Slide 4

Slide 4 text

What is Asynchrony? • Events that occur outside the main program flow • Concurrency • Non-blocking I/O • Parallelism Procedure Procedure Procedure Async Event Async Event

Slide 5

Slide 5 text

Asynchronous Events

Slide 6

Slide 6 text

Asynchronous Events &1"; echo shell_exec($command); Primary Process Secondary Process

Slide 7

Slide 7 text

Asynchronous programming describes a set of techniques designed to parallelize work and minimize idleness. Operation 1 Operation 2 Operation 3 Operation 1 Operation 2 Operation 3 Op1 Op 2 Op 3 Op 2 Op1 Op 3 Op1

Slide 8

Slide 8 text

Async in PHP • Promises/Futures • Asynchronous I/O • Hack Async • Threads (haha, only joking!)

Slide 9

Slide 9 text

A Promise for the Future

Slide 10

Slide 10 text

A Rose By Another Name • Promises • Futures • Delays • Deferred

Slide 11

Slide 11 text

Promise Fulfilled Rejected

Slide 12

Slide 12 text

Multi-RPC

Slide 13

Slide 13 text

Client sends a payload { requests: [ posts.query({“status”: “published”}), slideshows.query({“status”: “published”}) ] } API executes procedures asynchronously When procedures are all done, API returns { responses: [ posts.query: { … }, slideshows.query: { … }) ] }

Slide 14

Slide 14 text

What about HTTP Requests? {% set request1 = http('http://example.com/service-foo') %} {% set request2 = http('http://example.com/service-bar') %} {% set request3 = http('http://example.com/service-baz') %} Foo{{ request1.body.field }} Bar{{ request2.body.field }} Baz{{ request3.body.field }} 233ms 318ms 188ms 739ms

Slide 15

Slide 15 text

$pool = new Pool($client, $requests, [ 'concurrency' => 10, 'fulfilled' => $complete, 'rejected' => $complete ]); $pool->promise()->wait(); For each request, we create a Promise. A Promise represents an eventual result. We wait for all Promises to be Fulfilled or Rejected Gather requests Execute request 1 Execute request 2 Execute request 3 Execute request 4 Return responses

Slide 16

Slide 16 text

then( // onFulfilled function ($value) { echo "Promise fulfilled successfully! - " . $value; }, // onRejected function ($reason) { echo "Promise rejected! :( - " . $reason; } ); $promise->resolve("OpenWest");

Slide 17

Slide 17 text

The Point of Promises do(); if (!$done) { throw new NotDoneException("Didn't do the thing! :("); } return $done; } try { $doneThing = doTheThing(new Thing()); echo $doneThing; } catch (NotDoneException $exc) { echo $exc->getMessage(); }

Slide 18

Slide 18 text

The Point of Promises then( function (Thing $thing): string { $done = $this->do(); if (!$done) { throw new NotDoneException("Didn't do the thing! :("); } return $done; } ) ->capture( function (NotDoneException $e) { echo $e->getMessage(); } ) ->done( function (string $value) { echo $value; } ) ;

Slide 19

Slide 19 text

Asynchronous Functions • Can’t return values because there’s nothing to receive them • Can’t throw exceptions because there’s nothing to catch them • Promises allow us to compose the results of async functions and handle errors from async functions. • Promises are a paradigmatic translation layer!

Slide 20

Slide 20 text

Blocking I/O • When we read from or write to disk • When we read from or write to a network connection • Communicating with an external service (DB, API, etc)

Slide 21

Slide 21 text

Format Time (s) Equivalent Distance Equivalent Time 1 CPU Cycle 0.3 ns 1 m (1 step) 1 second L1 Cache 0.9 ns 3 m (3 steps) 3 seconds Main Memory 120 ns 360 m (US Capitol Grounds) 6 minutes SSD 50 µs 170 km (Prishtina) 2 days HDD 5 ms 13,000 km (Falkland Islands) 5 months

Slide 22

Slide 22 text

Event Loops

Slide 23

Slide 23 text

Slide 24

Slide 24 text

Slide 25

Slide 25 text

0) { $chunk = ""; do { $chunk = fread($fd, 512 - strlen($data)); $data .= $chunk; } while ($chunk !== "" && strlen($data) < 512); } } fclose($fd); echo $data;

Slide 26

Slide 26 text

Event Loops in PHP • ReactPHP (mature, supports stream_select & libevent) • Icicle (newer, supports stream_select, libevent, & libuv)

Slide 27

Slide 27 text

Non-Blocking Server on('connection', function ($conn) { usleep(500000); $conn->write(str_repeat('a', 1024)); $conn->end(); }); echo "Socket server listening on port 4000.\n"; echo "You can connect to it by running: telnet localhost 4000\n"; $socket->listen(4000); $loop->run();

Slide 28

Slide 28 text

Events • File descriptor (socket) polling. Incoming connections, data, etc. • Callbacks, aka ticks • One-off timers • Periodic timers

Slide 29

Slide 29 text

Callbacks $socket->on('connection', function ($conn) { usleep(500000); $conn->write(str_repeat('a', 1024)); $conn->end(); }); on the event ‘connection’ execute the given function

Slide 30

Slide 30 text

App tells kernel “read from socket 42” Kernel enqueues request App continues to run Kernel reads data and throws event App handles event (executes callback)

Slide 31

Slide 31 text

on( 'request', function (\React\Http\Request $request, \React\Http\Response $response) use (&$counter, &$loop) { $counter++; echo "Handling request number $counter" . PHP_EOL; $headers = ['Content-Type' => 'text/html']; $response->writeHead(200, $headers); $process = new \React\ChildProcess\Process('fortune'); $process->start($loop); $process->stdout->on( 'data', function ($output) use (&$response) { $response->write($output); } ); $process->on( 'exit', function ($rc, $signal) use (&$response) { $response->end(); } ); } ); echo "Socket server listening on port 4000.\n"; echo "You can connect to it by running: telnet localhost 4000\n"; $socket->listen(4000); $loop->run();

Slide 32

Slide 32 text

What about Hack?

Slide 33

Slide 33 text

Hack’s Approach • Async functions are marked with an ‘async’ keyword • Functions return an `Awaitable` • Awaitables are similar to promises - they represent a future value

Slide 34

Slide 34 text

Slide 35

Slide 35 text

{ $n1 = 0; $n2 = 1; $n3 = 1; for ($i = 2; $i < $n; ++$i) { $n3 = $n1 + $n2; $n1 = $n2; $n2 = $n3; } return (float)$n3; } async function getData(): Awaitable { return file_get_contents('data/data.txt'); } async function printData(): Awaitable { $fib = fibonacci(1024); $data = getData(); $results = await \HH\Asio\v([$fib, $data]); echo join(PHP_EOL, $results); } printData();

Slide 36

Slide 36 text

{ $n1 = 0; $n2 = 1; $n3 = 1; for ($i = 2; $i < $n; ++$i) { $n3 = $n1 + $n2; $n1 = $n2; $n2 = $n3; if (!($n%100)) { await RescheduleWaitHandle::create(RescheduleWaitHandle::QUEUE_DEFAULT, 0); } } return (float)$n3; } async function getData(): Awaitable { return file_get_contents('data/data.txt'); } async function printData(): Awaitable { $fib = fibonacci(1024); $data = getData(); $results = await \HH\Asio\v([$fib, $data]); echo join(PHP_EOL, $results); } printData();

Slide 37

Slide 37 text

Why Async? • Tackling the C10K (or C10M!) problem • Minimize latency and idleness - these are cost killers! • (Possibly) cleaner separations of concerns

Slide 38

Slide 38 text

Async & PHP • async-interop • Core support?

Slide 39

Slide 39 text

Things to Remember • Async is not always faster than sync. Sometimes it’s slower. • It can be hard to conceptualize the benefits of async in the mind • It can be hard to recognize the benefits of async on a laptop

Slide 40

Slide 40 text

References • https://icicle.io/docs/manual/introduction/ • http://php.net/manual/en/function.stream-select.php • https://blog.domenic.me/youre-missing-the-point-of-promises/ • https://www.sitepoint.com/an-introduction-into-event-loops-in-php/ • http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/ • http://blog.kgriffs.com/2012/09/18/demystifying-async-io.html • https://docs.hhvm.com/hack/async/introduction

Slide 41

Slide 41 text

New Tweeps! Also, thanks guys!