ARKADIUSZ KONDAS
Lead Software Architect
@ Proget Sp. z o.o.
Zend Certified Engineer
Code Craftsman
Blogger
Ultra Runner
@ ArkadiuszKondas
itcraftsman.pl
Zend Certified Architect
$urls = ['amazon.com', 'ebay.com', 'allegro.pl'];
foreach ($urls as $url) {
$content = file_get_contents(
sprintf('http://%s', $url)
);
}
amazon.com: 1.3739
ebay.com: 1.4950
allegro.pl: 0.4184
Total time: 3.2877
Latency numbers every programmer should know
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
Latency numbers every programmer should know
L1 cache reference 0.5 s One heart beat (0.5 s)
Branch mispredict 5 s Yawn
L2 cache reference 7 s Long yawn
Mutex lock/unlock 25 s Making a coffee
Main memory reference 100 s Brushing your teeth
Compress 1K bytes with Zippy 50 min One episode of a TV show
(including ad breaks)
Send 2K bytes over 1 Gbps network 5.5 hr From lunch to end of work day
SSD random read 1.7 days A normal weekend
Read 1 MB sequentially from memory 2.9 days A long weekend
Round trip within same datacenter 5.8 days A medium vacation
Read 1 MB sequentially from SSD 11.6 days Waiting for almost 2 weeks
for a delivery
Disk seek 16.5 weeks A semester in university
Read 1 MB sequentially from disk 7.8 months Almost producing a new
human being
The above 2 together 1 year
Send packet CA->Netherlands->CA 4.8 years Average time it takes to
complete a bachelor's degree
You can buy a 1000MHz machine with 2 gigabytes of RAM and an 1000Mbit/sec Ethernet card for $1200 or so. Let's see - at 20000 clients, that's 50KHz, 100Kbytes, and 50Kbits/sec per client.
It shouldn't take any more horsepower than that to take four kilobytes from the disk and send them to the network once a second for each of twenty thousand clients.
So hardware is no longer the bottleneck. (Dan Kegel)
10–12 million connections (MigratoryData, 12 cores, using Java on Linux
https://mrotaru.wordpress.com/2013/10/10/scaling-to-12-million-concurrent-connections-how-migratorydata-did-it/
Threads
Apache
Multiplexing
kevent/select/pool
var http = require('http');
var urls = ['amazon.com', 'ebay.com', 'allegro.pl'];
for (let i in urls) {
http.get('http://' + urls[i], function(response){
var str = '';
response.on('data', function(chunk) {
str += chunk;
});
response.on('end', function(){});
});
}
allegro.pl: 0.3901
amazon.com: 0.4755
ebay.com: 0.6653
Total time: 0.6756
amazon.com: 1.3739
ebay.com: 1.4950
allegro.pl: 0.4184
Total time: 3.2877
SELECT(2) Linux Programmer's Manual
NAME
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing
SYNOPSIS
/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout,
const sigset_t *sigmask);
DESCRIPTION
select() and pselect() allow a program to monitor multiple file descriptors,
waiting until one or more of the file descriptors become "ready" for some class
of I/O operation (e.g., input possible). A file descriptor is considered
ready if it is possible to perform a corresponding I/O operation (e.g., read(2)
without blocking, or a sufficiently small write(2)).
<?php
$readable = [stream_socket_client(), stream_socket_client()];
$writable = $writeStreams;
$except = [];
while(true) {
if (stream_select($readable, $writable, $except, 1)) {
foreach ($readable as $stream) {
}
foreach ($writable as $stream) {
}
}
}
EventEmmiter
EventLoop
Stream
Socket
ChildProcess
DNS
Http
HttpClient
Stomp
ØMQ
Whois
Redis
WebSockets
AR.drone
Promise
Filesystem
$emitter = new Evenement\EventEmitter();
$emitter->on('data', function ($data) {
echo $data;
});
$emitter->emit('data', [$data]);
$loop = React\EventLoop\Factory::create();
$server = stream_socket_server('tcp://127.0.0.1:8080');
stream_set_blocking($server, 0);
$loop->addReadStream($server, function ($server) use ($loop) {
$conn = stream_socket_accept($server);
$loop->addWriteStream($conn, function ($conn) {
});
});
$loop->addPeriodicTimer(5, function () {
$memory = memory_get_usage() / 1024;
$formatted = number_format($memory, 3).'K';
echo "Current memory usage: {$formatted}\n";
});
$loop->run();
interface ReadableStreamInterface
{
public function isReadable();
public function pause();
public function resume();
public function close();
public function pipe(WritableStreamInterface $dest, array $options = array());
}
Events: data, error, end, close
interface WritableStreamInterface
{
public function isWritable();
public function write($data);
public function end($data = null);
public function close();
}
Events: drain, error, close, pipe
use React\EventLoop\Factory;
use React\Stream\ReadableResourceStream;
use React\Stream\WritableResourceStream;
$loop = Factory::create();
$source = new ReadableResourceStream(
fopen('omg.txt', 'r'), $loop
);
$dest = new WritableResourceStream(
fopen('wtf.txt', 'w'), $loop
);
$source->pipe($dest);
$loop->run();
$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server(8080, $loop);
$socket->on('connection', function (ConnectionInterface $conn) {
$conn->write("Hello " . $conn->getRemoteAddress() . "!\n");
$conn->write("Welcome to this amazing server!\n");
$conn->write("Here's a tip: don't say anything.\n");
$conn->on('data', function ($data) use ($conn) {
$conn->close();
});
});
$loop->run();
$urls = ['...', '...'];
$promises = [];
foreach($urls as $url) {
$deferred = new Promise\Deferred();
$request = $client->request('GET', $url);
$request->on('response',
function ($response) use ($deferred, $url) {
$response->on('end', function ($data) use ($deferred, $url) {
$deferred->resolve($url);
});
});
$request->end();
$promises[] = $deferred->promise();
}
Promise\race($promises)->then(function($value) {
echo $value . " wins the race!" . PHP_EOL;
});
$loop = \React\EventLoop\Factory::create();
$factory = new \React\Dns\Resolver\Factory();
$dns = $factory->create('8.8.8.8', $loop);
$dns->resolve($argv[1])
->then(
function ($ip) { echo "Host: $ip\n"; },
function ($error) { echo "Error: {$error->getMessage()}\n"; }
);
$loop->run();
php bin/promise.php 4developers.pl
Host: 87.98.239.5
php bin/promise.php aaa
Error: DNS Request did not return valid answer.
$loop = React\EventLoop\Factory::create();
$process = new React\ChildProcess\Process('echo foo');
$process->start($loop);
$process->stdout->on('data', function ($chunk) {
echo $chunk;
});
$process->on('exit', function($exitCode, $termSignal) {
echo 'Process exited with code ' . $exitCode . PHP_EOL;
});
$loop->run();
<?php
$client->on('data', function ($data) use ($client, &$clients) {
$data = trim(preg_replace('/[^\w\d \.\,\-\!\?]/u', '', $data));
if ($data === '') {
return;
}
$data = $client->getRemoteAddress() . ': ' . $data . PHP_EOL;
$otherClients = array_filter($clients, function (ConnectionInterface $c) use ($client) {
return $c!==$client;
});
array_walk($otherClients, function(ConnectionInterface $c) use ($data){
$c->write($data);
});
});
Text
VS
https://philsturgeon.uk/php/2013/11/12/benchmarking-codswallop-nodejs-v-php/
https://github.com/itcraftsmanpl/php-smasher
http://socketo.me/
https://github.com/nrk/predis-async
https://github.com/reactphp/zmq
https://github.com/reactphp/stomp
https://github.com/jolicode/php-ar-drone
$drone->on('landed', function() {
// do something
});
$drone
->after(3, function () use ($drone) {
$drone->up(0.6);
})
->after(4, function () use ($drone) {
$drone->stop();
})
->after(1, function () use ($drone) {
$drone->left(0.3);
})
$drone->start();
opcache
please enable opcache
https://github.com/php-pm/php-pm
Asynchronous Multitasking PHP: Hypertext Preprocessor
https://github.com/amphp
function slowAddition($x, $y) {
sleep(1);
return $x + $y;
}
$dispatcher = new Amp\Thread\Dispatcher;
$a = $dispatcher->call('slowAddition', 1, 5);
$b = $dispatcher->call('slowAddition', 10, 10);
$c = $dispatcher->call('slowAddition', 11, 31);
$comboPromise = Amp\all([$a, $b, $c]);
list($a, $b, $c) = $comboPromise->wait();
https://github.com/swoole/swoole-src
Swoole is an event-driven asynchronous & concurrent networking communication framework with high performance written only in C for PHP.
http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html
Cooperative multitasking using coroutines (in PHP!)
by Nikita Popov
@ ArkadiuszKondas
https://github.com/itcraftsmanpl/php-smasher