14 August 2015

ReactPHP ускоряет PHPixie в 8 раз

Website developmentPHP
image
ReactPHP это сокет сервер на PHP созданный для постоянной обработки запросов в отличии от стандартного подхода с Apache и Nginx где процесс умирает по окончании обработки одного запроса. Поскольку инициализация кода таким образом осуществляется только один раз то на отдельном запросе мы упускаем весь оверхед от загрузки классов, запуска фреймворка, считывания конфигурации итд.

Ограничением тут является то, что программист должен помнить что процесс и все поднятые сервисы будут использованы множество раз и по этому доступ к глобальному или статическому скоупу не желателен. Это делает сложным использование ReactPHP с большинством фреймворков не созданных для такого подхода.

К счастью PHPixie сама отказалась от глобального и статического скоупов, что позволяет легко запустить ее из-под ReactPHP.


Для начала добавим его поддержку в проект:
php ~/composer.phar require react/react


Затем создаем файл react.php в корневой папке:
<?php

require_once('vendor/autoload.php');

$host = 'localhost';
$port = 1337;

$framework = new Project\Framework();
$framework->registerDebugHandlers(false, false);

$app = function ($request, $response) use ($framework, $host, $port) {
    $http = $framework->builder()->components()->http();

    // Строим реальную URI запроса
    $uri = 'http://'.$host.':'.$port.$request->getPath();
    $uri = $http->messages()->uri($uri);

    // Приводим запрос к PSR-7
    $serverRequest = $http->messages()->serverRequest(
        $request->getHttpVersion(),
        $request->getHeaders(),
        '',
        $request->getMethod(),
        $uri,
        array(),
        $request->getQuery(),
        array(),
        array(),
        array()
    );

    // Передаем запрос в фреймворк
    $frameworkResponse = $framework
        ->processHttpServerRequest($serverRequest);

    // Вывод ответа
    $response->writeHead(
        $frameworkResponse->getStatusCode(),
        $frameworkResponse->getHeaders()
    );
    $response->end(
        $frameworkResponse->getBody()
    );
};

$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket);

$http->on('request', $app);

$socket->listen($port);
$loop->run();


Запускаем:
php react.php


Теперь перейдя по ссылке localhost:1337/ видим ту же PHPixie только запущенную как сервер. Простой бенчмарк на дефолтном контроллере показал увеличение производительности примерно в 8 раз, что не удивительно если взять во внимание то на сколько меньше кода выполняется при каждом запросе. Для тех кто захочет повторить мой эксперимент заметьте что я добился наилучшего результата с библиотекой event как бекенда для ReactPHP (он может работать и без нее, но только чуть медленнее получается).

Правда сам ReactPHP вносит несколько ограничений. Во-первых вам все равно понадобится веб-сервер для статических файлов. Но самое грустное то, что из коробки он не поддерживает данные из тела запроса ($_POST), хотя существуют способы добиться этого.

Наличие постоянного рантайма открывает интересные возможности, как например создание чата без надобности во внешней базе данных. Конечно пока-что это только эксперимент, но если идея приживется то PHPixie может получить отдельный компонент с более широкой поддержкой ReactPHP, включая например сессии и загрузку файлов.
Tags: php phpixie reactphp фреймворк
Hubs: Website development PHP
+9
15.7k 70
Comments 42
Ads