Skip to content

Add benchmarking example #162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 7, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions examples/99-benchmark-download.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

// $ php examples/99-benchmark-download.php 8080
// $ curl http://localhost:8080/10g.bin > /dev/null
// $ wget http://localhost:8080/10g.bin -O /dev/null
// $ ab -n10 -c10 http://localhost:8080/1g.bin
// $ docker run -it --rm --net=host jordi/ab ab -n10 -c10 http://localhost:8080/1g.bin

use React\EventLoop\Factory;
use React\Socket\Server;
use React\Http\Response;
use Psr\Http\Message\RequestInterface;
use React\Stream\ReadableStream;

require __DIR__ . '/../vendor/autoload.php';

$loop = Factory::create();
$socket = new Server(isset($argv[1]) ? $argv[1] : '0.0.0.0:0', $loop);

/** A readable stream that can emit a lot of data */
class ChunkRepeater extends ReadableStream
{
private $chunk;
private $count;
private $position = 0;
private $paused = true;

public function __construct($chunk, $count)
{
$this->chunk = $chunk;
$this->count = $count;
}

public function pause()
{
$this->paused = true;
}

public function resume()
{
if (!$this->paused) {
return;
}

// keep emitting until stream is paused
$this->paused = false;
while ($this->position < $this->count && !$this->paused) {
++$this->position;
$this->emit('data', array($this->chunk));
}

// end once the last chunk has been written
if ($this->position >= $this->count) {
$this->emit('end');
$this->close();
}
}

public function getSize()
{
return strlen($this->chunk) * $this->count;
}
}

$server = new \React\Http\Server($socket, function (RequestInterface $request) use ($loop) {
switch ($request->getUri()->getPath()) {
case '/':
return new Response(
200,
array('Content-Type' => 'text/html'),
'<html><a href="1g.bin">1g.bin</a><br/><a href="10g.bin">10g.bin</a></html>'
);
case '/1g.bin':
$stream = new ChunkRepeater(str_repeat('.', 1000000), 1000);
break;
case '/10g.bin':
$stream = new ChunkRepeater(str_repeat('.', 1000000), 10000);
break;
default:
return new Response(404);
}

$loop->addTimer(0, array($stream, 'resume'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a future tick instead here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both would work here 👍 Using a timer here also makes this compatible with react/event-loop:^0.3 though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 👍


return new Response(
200,
array('Content-Type' => 'application/octet-data', 'Content-Length' => $stream->getSize()),
$stream
);
});

echo 'Listening on http://' . $socket->getAddress() . PHP_EOL;

$loop->run();