moebiusphp/moebius

[Question] Examples showing performance benefits

rutek opened this issue · 5 comments

rutek commented

Hello, do you have any examples which shows that blocking functions are really paused and executed when result is available? I am talking about something like https://github.com/frodeborli/moebius/blob/master/examples/async-tcp/async-tcp.php but when executing for example 20 requests. I have tried to implement such test but I cannot get any results with execution time better than synchronous execution

Have a good day! :)

Hi, and thank you for your question.

I am aware of this problem and the solution is quite simple; I haven’t had time to focus on it because I have been busy on the core and interoperability with frameworks and extensions such as React/Amp/Swoole/ext-ev.

To make this transparent, we need to write a custom HTTP stream wrapper (to override the built-in http:// and https:// streams).

I already did it for the file:// protocol. I tried the same approach for the http protocols but it can’t be fixed the same way unfortunately.

In short:

I need a stream wrapper which uses `fsockopen()' to perform the HTTP request. Once the stream is opened, it should make the stream “unblocked”.

$fp = fsockopen("tcp://up-address");
$fp = Moebius\Coroutine::unblock($fp);

as long as this is in place, you should get concurrency. This trick works for any stream resource client. I could fork Guzzle to do it there. The only problem is to make it a stream wrapper next, which I haven’t time for yet:)

@rutek I found a stream wrapper implementation for the httplug HTTP client here:

https://github.com/php-http/httplug-stream-wrapper/blob/master/src/StreamWrapper.php

Next step would be to fork this client: https://packagist.org/packages/php-http/socket-client

So that the stream socket gets managed via Coroutine::unblock()

Today I finished a major refactor of the core, and I have moved this repo to the moebiusphp organization.

I will be able to work on this now. It is an essential feature. With the refactor Moebius is able to run on other event loops such as React or Amp, and so can leverage their entire ecosystems.

I didn’t want to start on this feature until the core was simpler and I had a consistent design for all the important capabilities.

Today I finished a major refactor of the core, and I have moved this repo to the moebiusphp organization.

I will be able to work on this now. It is an essential feature. With the refactor Moebius is able to run on other event loops such as React or Amp, and so can leverage their entire ecosystems.

I didn’t want to start on this feature until the core was simpler and I had a consistent design for all the important capabilities.

Is it already released? If would be glad if you could share how to use it with i.e. react loop.

Hi, I have now released a version I am satisfied with (version 1.0.100). There are probably some more issues to work out, but I haven't found any issues which aren't related to incorrect usage of Moebius.

The easiest way to try it out is by installing moebius/moebius via composer, for example with React server:

composer require react/http
composer require moebius/moebius

The following is a modification of the original example from react's website. I only wrapped the function body inside a `return Co::go(function() {}), which makes it run inside a coroutine.

From there on you can use functions like Co::sleep($seconds), Co::readable($fileResource), Co::writable($fileResource) and finally Co::await($promise).

File IO is asynchronous automatically, and I have worked on the HTTP stream wrapper - but didn't complete it yet, sorry.

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

use Moebius\Coroutine as Co;

$http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
    return Co::go(function() {
        Co::sleep(1);
        return React\Http\Message\Response::plaintext("Hello world!");
    });
});

$socket = new React\Socket\SocketServer('0.0.0.0:8080');
$http->listen($socket);

echo "Server running at http://0.0.0.0:8080" . PHP_EOL;