Skip to content
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

Global event-loop accessor part four #226

Merged
Show file tree
Hide file tree
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
36 changes: 30 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ single [`run()`](#run) call that is controlled by the user.

* [Quickstart example](#quickstart-example)
* [Usage](#usage)
* [Loop](#loop)
* [get()](#get)
* [Factory](#factory)
* [create()](#create)
* [Loop implementations](#loop-implementations)
Expand Down Expand Up @@ -45,32 +47,32 @@ single [`run()`](#run) call that is controlled by the user.
Here is an async HTTP server built with just the event loop.

```php
$loop = React\EventLoop\Factory::create();
use React\EventLoop\Loop;

$server = stream_socket_server('tcp://127.0.0.1:8080');
stream_set_blocking($server, false);

$loop->addReadStream($server, function ($server) use ($loop) {
Loop::get()->addReadStream($server, function ($server) {
$conn = stream_socket_accept($server);
$data = "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nHi\n";
$loop->addWriteStream($conn, function ($conn) use (&$data, $loop) {
Loop::get()->addWriteStream($conn, function ($conn) use (&$data) {
$written = fwrite($conn, $data);
if ($written === strlen($data)) {
fclose($conn);
$loop->removeWriteStream($conn);
Loop::get()->removeWriteStream($conn);
} else {
$data = substr($data, $written);
}
});
});

$loop->addPeriodicTimer(5, function () {
Loop::get()->addPeriodicTimer(5, function () {
$memory = memory_get_usage() / 1024;
$formatted = number_format($memory, 3).'K';
echo "Current memory usage: {$formatted}\n";
});

$loop->run();
Loop::get()->run();
```

See also the [examples](examples).
Expand Down Expand Up @@ -110,6 +112,28 @@ $loop->run();
purposes.
3. The loop is run with a single [`$loop->run()`](#run) call at the end of the program.

### Loop

The `Loop` class exists as a convenient global accessor for the event loop.

#### get()

The `get(): LoopInterface` method is the preferred way to get and use the event loop. With
it there is no need to always pass the loop around anymore.

```php
use React\EventLoop\Loop;

Loop::get()->addTimer(0.02, function () {
echo 'World!';
});
Loop::get()->addTimer(0.01, function () {
echo 'Hello ';
});

Loop::get()->run();
```

### Factory

The `Factory` class exists as a convenient way to pick the best available
Expand Down
10 changes: 5 additions & 5 deletions examples/01-timers.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<?php

require __DIR__ . '/../vendor/autoload.php';
use React\EventLoop\Loop;

$loop = React\EventLoop\Factory::create();
require __DIR__ . '/../vendor/autoload.php';

$loop->addTimer(0.8, function () {
Loop::get()->addTimer(0.8, function () {
echo 'world!' . PHP_EOL;
});

$loop->addTimer(0.3, function () {
Loop::get()->addTimer(0.3, function () {
echo 'hello ';
});

$loop->run();
Loop::get()->run();
12 changes: 6 additions & 6 deletions examples/02-periodic.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<?php

require __DIR__ . '/../vendor/autoload.php';
use React\EventLoop\Loop;

$loop = React\EventLoop\Factory::create();
require __DIR__ . '/../vendor/autoload.php';

$timer = $loop->addPeriodicTimer(0.1, function () {
$timer = Loop::get()->addPeriodicTimer(0.1, function () {
echo 'tick!' . PHP_EOL;
});

$loop->addTimer(1.0, function () use ($loop, $timer) {
$loop->cancelTimer($timer);
Loop::get()->addTimer(1.0, function () use ($timer) {
Loop::get()->cancelTimer($timer);
echo 'Done' . PHP_EOL;
});

$loop->run();
Loop::get()->run();
10 changes: 5 additions & 5 deletions examples/03-ticks.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<?php

require __DIR__ . '/../vendor/autoload.php';
use React\EventLoop\Loop;

$loop = React\EventLoop\Factory::create();
require __DIR__ . '/../vendor/autoload.php';

$loop->futureTick(function () {
Loop::get()->futureTick(function () {
echo 'b';
});
$loop->futureTick(function () {
Loop::get()->futureTick(function () {
echo 'c';
});
echo 'a';

$loop->run();
Loop::get()->run();
10 changes: 5 additions & 5 deletions examples/04-signals.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<?php

use React\EventLoop\Loop;

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

if (!defined('SIGINT')) {
fwrite(STDERR, 'Not supported on your platform (ext-pcntl missing or Windows?)' . PHP_EOL);
exit(1);
}

$loop = React\EventLoop\Factory::create();

$loop->addSignal(SIGINT, $func = function ($signal) use ($loop, &$func) {
Loop::get()->addSignal(SIGINT, $func = function ($signal) use (&$func) {
echo 'Signal: ', (string)$signal, PHP_EOL;
$loop->removeSignal(SIGINT, $func);
Loop::get()->removeSignal(SIGINT, $func);
});

echo 'Listening for SIGINT. Use "kill -SIGINT ' . getmypid() . '" or CTRL+C' . PHP_EOL;

$loop->run();
Loop::get()->run();
10 changes: 4 additions & 6 deletions examples/11-consume-stdin.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

use React\EventLoop\Factory;
use React\EventLoop\Loop;

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

Expand All @@ -9,16 +9,14 @@
exit(1);
}

$loop = Factory::create();

// read everything from STDIN and report number of bytes
// for illustration purposes only, should use react/stream instead
$loop->addReadStream(STDIN, function ($stream) use ($loop) {
Loop::get()->addReadStream(STDIN, function ($stream) {
$chunk = fread($stream, 64 * 1024);

// reading nothing means we reached EOF
if ($chunk === '') {
$loop->removeReadStream($stream);
Loop::get()->removeReadStream($stream);
stream_set_blocking($stream, true);
fclose($stream);
return;
Expand All @@ -27,4 +25,4 @@
echo strlen($chunk) . ' bytes' . PHP_EOL;
});

$loop->run();
Loop::get()->run();
10 changes: 5 additions & 5 deletions examples/12-generate-yes.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use React\EventLoop\Loop;

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

// data can be given as first argument or defaults to "y"
Expand All @@ -8,22 +10,20 @@
// repeat data X times in order to fill around 200 KB
$data = str_repeat($data, round(200000 / strlen($data)));

$loop = React\EventLoop\Factory::create();

if (!defined('STDOUT') || stream_set_blocking(STDOUT, false) !== true) {
fwrite(STDERR, 'ERROR: Unable to set STDOUT non-blocking (not CLI or Windows?)' . PHP_EOL);
exit(1);
}

// write data to STDOUT whenever its write buffer accepts data
// for illustrations purpose only, should use react/stream instead
$loop->addWriteStream(STDOUT, function ($stdout) use ($loop, &$data) {
Loop::get()->addWriteStream(STDOUT, function ($stdout) use (&$data) {
// try to write data
$r = fwrite($stdout, $data);

// nothing could be written despite being writable => closed
if ($r === 0) {
$loop->removeWriteStream($stdout);
Loop::get()->removeWriteStream($stdout);
fclose($stdout);
stream_set_blocking($stdout, true);
fwrite(STDERR, 'Stopped because STDOUT closed' . PHP_EOL);
Expand All @@ -38,4 +38,4 @@
}
});

$loop->run();
Loop::get()->run();
10 changes: 4 additions & 6 deletions examples/13-http-client-blocking.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
<?php

use React\EventLoop\Factory;
use React\EventLoop\Loop;

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

$loop = Factory::create();

// connect to www.google.com:80 (blocking call!)
// for illustration purposes only, should use react/socket instead
$stream = stream_socket_client('tcp://www.google.com:80');
Expand All @@ -18,18 +16,18 @@
fwrite($stream, "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n");

// wait for HTTP response
$loop->addReadStream($stream, function ($stream) use ($loop) {
Loop::get()->addReadStream($stream, function ($stream) {
$chunk = fread($stream, 64 * 1024);

// reading nothing means we reached EOF
if ($chunk === '') {
echo '[END]' . PHP_EOL;
$loop->removeReadStream($stream);
Loop::get()->removeReadStream($stream);
fclose($stream);
return;
}

echo $chunk;
});

$loop->run();
Loop::get()->run();
17 changes: 8 additions & 9 deletions examples/14-http-client-async.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<?php

use React\EventLoop\Factory;
use React\EventLoop\Loop;

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

$loop = Factory::create();

// resolve hostname before establishing TCP/IP connection (resolving DNS is still blocking here)
// for illustration purposes only, should use react/socket or react/dns instead!
$ip = gethostbyname('www.google.com');
Expand All @@ -24,14 +23,14 @@

// print progress every 10ms
echo 'Connecting';
$timer = $loop->addPeriodicTimer(0.01, function () {
$timer = Loop::get()->addPeriodicTimer(0.01, function () {
echo '.';
});

// wait for connection success/error
$loop->addWriteStream($stream, function ($stream) use ($loop, $timer) {
$loop->removeWriteStream($stream);
$loop->cancelTimer($timer);
Loop::get()->addWriteStream($stream, function ($stream) use ($timer) {
Loop::get()->removeWriteStream($stream);
Loop::get()->cancelTimer($timer);

// check for socket error (connection rejected)
if (stream_socket_get_name($stream, true) === false) {
Expand All @@ -45,13 +44,13 @@
fwrite($stream, "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n");

// wait for HTTP response
$loop->addReadStream($stream, function ($stream) use ($loop) {
Loop::get()->addReadStream($stream, function ($stream) {
$chunk = fread($stream, 64 * 1024);

// reading nothing means we reached EOF
if ($chunk === '') {
echo '[END]' . PHP_EOL;
$loop->removeReadStream($stream);
Loop::get()->removeReadStream($stream);
fclose($stream);
return;
}
Expand All @@ -60,4 +59,4 @@
});
});

$loop->run();
Loop::get()->run();
14 changes: 7 additions & 7 deletions examples/21-http-server.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?php

require __DIR__ . '/../vendor/autoload.php';
use React\EventLoop\Loop;

$loop = React\EventLoop\Factory::create();
require __DIR__ . '/../vendor/autoload.php';

// start TCP/IP server on localhost:8080
// for illustration purposes only, should use react/socket instead
Expand All @@ -13,24 +13,24 @@
stream_set_blocking($server, false);

// wait for incoming connections on server socket
$loop->addReadStream($server, function ($server) use ($loop) {
Loop::get()->addReadStream($server, function ($server) {
$conn = stream_socket_accept($server);
$data = "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nHi\n";
$loop->addWriteStream($conn, function ($conn) use (&$data, $loop) {
Loop::get()->addWriteStream($conn, function ($conn) use (&$data) {
$written = fwrite($conn, $data);
if ($written === strlen($data)) {
fclose($conn);
$loop->removeWriteStream($conn);
Loop::get()->removeWriteStream($conn);
} else {
$data = substr($data, $written);
}
});
});

$loop->addPeriodicTimer(5, function () {
Loop::get()->addPeriodicTimer(5, function () {
$memory = memory_get_usage() / 1024;
$formatted = number_format($memory, 3).'K';
echo "Current memory usage: {$formatted}\n";
});

$loop->run();
Loop::get()->run();
8 changes: 3 additions & 5 deletions examples/91-benchmark-ticks.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
<?php

use React\EventLoop\Factory;
use React\EventLoop\Loop;

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

$loop = Factory::create();

$n = isset($argv[1]) ? (int)$argv[1] : 1000 * 100;

for ($i = 0; $i < $n; ++$i) {
$loop->futureTick(function () { });
Loop::get()->futureTick(function () { });
}

$loop->run();
Loop::get()->run();
Loading