Slide 1

Slide 1 text

React.PHP

Slide 2

Slide 2 text

K. k47.cz @kaja47 Karel Čížex funkcionalne.cz

Slide 3

Slide 3 text

http://reactphp.org/

Slide 4

Slide 4 text

There's nothing we cannot steal. Let's steal node.js

Slide 5

Slide 5 text

node.js? PHP? wat?

Slide 6

Slide 6 text

event driven, non-blocking, reactive, async IO

Slide 7

Slide 7 text

buzzword, buzzword, buzzword, buzzword

Slide 8

Slide 8 text

CPU je rychlé, IO je pomalé

Slide 9

Slide 9 text

L1 cache reference ......................... 0.5 ns Branch mispredict ............................ 5 ns L2 cache reference ........................... 7 ns Mutex lock/unlock ........................... 25 ns Main memory reference ...................... 100 ns Compress 1K bytes with Zippy ............. 3,000 ns = 3 µs Send 2K bytes over 1 Gbps network ....... 20,000 ns = 20 µs SSD random read ........................ 150,000 ns = 150 µs Read 1 MB sequentially from memory ..... 250,000 ns = 250 µs Round trip within same datacenter ...... 500,000 ns = 0.5 ms Read 1 MB sequentially from SSD ...... 1,000,000 ns = 1 ms Disk seek ........................... 10,000,000 ns = 10 ms Read 1 MB sequentially from disk .... 20,000,000 ns = 20 ms Send packet CA->Netherlands->CA .... 150,000,000 ns = 150 ms

Slide 10

Slide 10 text

c10k

Slide 11

Slide 11 text

Na IO musíme čekat

Slide 12

Slide 12 text

Čekání blokuje vlákno

Slide 13

Slide 13 text

Potřebujeme hodně vláken

Slide 14

Slide 14 text

Vlákna zabírají paměť

Slide 15

Slide 15 text

10k vláken zabere hodně paměti

Slide 16

Slide 16 text

c10M

Slide 17

Slide 17 text

async non-blocking = 1 vlákno

Slide 18

Slide 18 text

epoll

Slide 19

Slide 19 text

stream_select(&$readable, &$writable, &$exc, $timeout)

Slide 20

Slide 20 text

while (true) { ... stream_select($readable, $writable, $err, $timeout) ... }

Slide 21

Slide 21 text

>-(IO)->-(IO)---------------------->-(IO)---->-(CPU)->-(CPU)->-(CPU)-> >-(IO)->-(CPU)-> >-(IO)---------------------->-(CPU)-> >-(IO)----> -(CPU)->

Slide 22

Slide 22 text

Reaktivní aplikace WebSockets Async end-to-end Par { MySQL, Redis, HTTP, FS } Cron

Slide 23

Slide 23 text

React.PHP (gory details)

Slide 24

Slide 24 text

Http Socket Stream EventLoop

Slide 25

Slide 25 text

HttpClient | DNS | WebSocket | ZeroMQ Socket Stream EventLoop

Slide 26

Slide 26 text

$loop = React\EventLoop\Factory::create(); $socket = new React\Socket\Server($loop); $http = new React\Http\Server($socket, $loop); $http->on('request', function ($request, $response) { $response->writeHead(200, ['Content-Type' => 'text/plain']); $response->end("Hello World\n"); }); $socket->listen(1337); $loop->run();

Slide 27

Slide 27 text

Server napsaný v PHP, který běží v PHP procesu

Slide 28

Slide 28 text

Jednovláknový

Slide 29

Slide 29 text

$loop->addPeriodicTimer(60*60*24*7, function ($timer) { hideBodies(ALL_OF_THEM); });

Slide 30

Slide 30 text

http://autotweeter.k47.cz

Slide 31

Slide 31 text

In-memory

Slide 32

Slide 32 text

http://onlyoc.jdem.cz

Slide 33

Slide 33 text

worker --> DB <-- Apache worker ------------> React

Slide 34

Slide 34 text

[your ad here]

Slide 35

Slide 35 text

callbax: call(function ($a) { call(function ($b) use ($a) { call(function ($c) use ($a, $b) { throw new Exception('Where is your god now?'); }); }); });

Slide 36

Slide 36 text

callbax: $http->on('connect', function ($req, $resp) { $req->on('data', function ($postData) { parse_str($postData, $post); $users->getById($post['id'], function ($err, $user) { renderUser($user, $resp); }); } });

Slide 37

Slide 37 text

callback == continuation

Slide 38

Slide 38 text

Callback hell Composition Coordination

Slide 39

Slide 39 text

Promise!

Slide 40

Slide 40 text

Deferred / Resolved / Rejected

Slide 41

Slide 41 text

Promise = hodnota (FP) Callback = proces

Slide 42

Slide 42 text

Promise[IO]

Slide 43

Slide 43 text

->then($ok, $err)

Slide 44

Slide 44 text

Callback hell Hodnota vs. proces

Slide 45

Slide 45 text

Kompozice $p->then($f)->then($g) (chyby) throw

Slide 46

Slide 46 text

// map (Functor) fetchPost($id)->then(function ($post) { return toJson($post, PRETTY); }); // flatMap (Monad) fetchPost($id)->then(function ($post) { return fetchPost($post->parentId); }); // robot unicorn attack loadFromCache()->then(null, 'loadFromDatabase')

Slide 47

Slide 47 text

$deferred = new React\Promise\Deferred(); $promise = $deferred->promise(); $resolver = $deferred->resolver(); $resolver->resolve('I\'m Boxxy you see') $resolver->reject(new \Exception('U dun goofed'));

Slide 48

Slide 48 text

React: Promise Resolver Scala: Future Promise C#: Task TaskCompletionSource

Slide 49

Slide 49 text

Koordinace

Slide 50

Slide 50 text

When::any($ps) When::some($ps, $n) When::all($ps) When::map($ps, $f) When::reduce($ps, $f) When::lazy($f)

Slide 51

Slide 51 text

$data = []; $callback = function($err, $val) use (&$data) { $data[] = $val; // pořadí? if (count($data) == 3) { realCallback($err, $data); } // chyby? chybějí! } fetch('ak', $callback); fetch('ruby', $callback); fetch('peo', $callback);

Slide 52

Slide 52 text

When::all(getUsers(), getCategories(), getLastPosts()); When::any(server(1), server(2), server(3)); When::all( When::map(getLastPost(), 'getComments'), getCategories(), getTweetsFromCache() ->then(null, 'fetchTweets') ->then('tranform', function () { return []; }) );

Slide 53

Slide 53 text

function timeout($time, $promise, $loop) { $defer = new React\Promise\Deferred; $r = $defer->resolver(); $sig = $loop->addTimer($time, function() use($r) { $r->reject('timeout'); }); $promise->then( function ($x) use($r, $sig, $loop) { $loop->cancelTimer($sig); $r->resolve($x); }, function ($e) use($r) { $r->reject($e); } ); return $defer->promise(); }

Slide 54

Slide 54 text

To je všechno pěkné, ale...

Slide 55

Slide 55 text

// fetch all followers $profile = fetchProfile('kaja47'); $ids = []; $cursor = '-1'; do { $fs = fetchFollowers($profile->id, $cursor); $ids = array_merge($ids, $fs->ids); $cursor = $fs->next_cursor_str; } while ($cursor != "0") return [$profile, $ids];

Slide 56

Slide 56 text

// async clusterfuck fetchProfile($userName)->then(function ($profile) { $fetch = function($userId, $cursor) use (&$fetch) { return fetchFollowers($userId, $cursor)->then(function ($fs) use ($userId) { $cursor = $fs->next_cursor_str; if ($cursor == "0") return When::resolve($fs->ids); else return $fetch($userId, $cursor)->then(function($ids) use($fs) { return array_merge($fs->ids, ids); }); }); }; $fetch($profile->id, '-1')->then(function($ids) use($ids) { return [$profile, $ids]; }) });

Slide 57

Slide 57 text

CPS

Slide 58

Slide 58 text

C# : async/await Iced Coffeescript: await/defer Scala: for/shift/reset/flow/makra

Slide 59

Slide 59 text

PHP 5.5 & yield

Slide 60

Slide 60 text

// async flow(function() { $profile = (yield fetchProfile('kaja47')); $ids = []; $cursor = '-1'; do { $fs = (yield fetchFollowers($profile->id, $cursor)); $ids = array_merge($ids, $fs->ids); $cursor = $fs->next_cursor_str; } while ($cursor != "0") yield [$profile, $ids]; });

Slide 61

Slide 61 text

function flow(Closure $f) { $gen = $f(); $fst = true; $recur = function($pureValue) use($gen, &$recur, &$fst) { $x = $fst ? $gen->current() : $gen->send($pureValue); $fst = false; if (!$gen->valid()) return $pureValue; if ($x instanceof Promise) return $x->then($recur); else return $recur($x); }; return $recur(null); }

Slide 62

Slide 62 text

[your ad here]

Slide 63

Slide 63 text

Co dál?

Slide 64

Slide 64 text

Reactive Nette

Slide 65

Slide 65 text

Async errything

Slide 66

Slide 66 text

FS HttpClient WebSocket Redis ZeroMQ STOMP (RabbitMQ) SOCKS IRC Dnode MySQL (non-reactive)

Slide 67

Slide 67 text

Výkon PHP < V8

Slide 68

Slide 68 text

Native async extension VM (JIT/tracing) GC Datové struktury

Slide 69

Slide 69 text

Rx Iteratees

Slide 70

Slide 70 text

popularita efektivita ⇒

Slide 71

Slide 71 text

This is the end Beautiful friend This is the end My only friend, the end Of our elaborate plans, the end Of everything that stands, the end No safety or surprise, the end I'll never look into your eyes...again Can you picture what will be So limitless and free Desperately in need...of some...stranger's hand In a...desperate land Lost in a Roman...wilderness of pain And all the children are insane All the children are insane Waiting for the summer rain, yeah

Slide 72

Slide 72 text

http://reactphp.org/ https://github.com/reactphp https://gist.github.com/hellerbarde/2843375 http://conference.phpnw.org.uk/phpnw12/schedule/igor-wiedler/#video http://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-promises-are-fu nctional-nodes-biggest-missed-opportunity/ http://blog.jcoglan.com/2013/04/01/callbacks-promises-and-simplicity/ https://gist.github.com/domenic/3889970 http://blog.parse.com/2013/01/29/whats-so-great-about-javascript-promises/ http://brianmckenna.org/blog/category_theory_promisesaplus http://www.dartlang.org/articles/using-future-based-apis/ http://marakana.com/s/post/1453/redemption_from_callback_hell_michael_ja ckson_domenic_denicola_video https://github.com/kaja47/flow https://github.com/kaja47/async-mysql https://gist.github.com/kaja47/4407844

Slide 73

Slide 73 text