Асинхронный WEB в 2018. Пишем чат на Websocket используя Swoole



Тема Websocket`ов уже не раз затрагивалась на Хабре, в частности рассматривались варианты реализации на PHP. Однако, с момента выхода последней статьи с обзором разных технологий прошло уже более года, а миру PHP есть чем похвастаться за прошедшее время.

В данной статье я хочу представить русскоязычному сообществу Swoole — Асинхронный Open Source фреймворк для PHP, написанный на Си, и поставляемый в виде pecl-расширения.

Посмотреть получившееся в итоге приложение(чат) можно: здесь.
Исходники на github.

Почему Swoole?


Наверняка найдутся люди, которые будут в принципе против использования PHP для таких целей, однако в пользу PHP часто могут играть:

  • Нежелание разводить зоопарк различных языков на проекте
  • Возможность использования уже наработанной кодовой базы(если проект на PHP).

Тем не менее, даже сравнивая с node.js/go/erlang и другими языками, нативно предлагающими асинхронную модель, Swoole — фреймворк написанный на Си и объеденивший в себе низкий порог вхождения и мощную функциональность может быть вполне хорошим кандидатом.

Возможности фреймворка:

  • Событийная, асинхронная модель программирования
  • Асинхронные TCP / UDP / HTTP / Websocket / HTTP2 клиентские/серверные API
  • Поддержка IPv4 / IPv6 / Unixsocket / TCP/ UDP и SSL / TLS
  • Быстрая сериализация / десериализация данных
  • Высокая производительность, расширяемость, поддержка до 1 миллиона одновременных соединений
  • Планировщик заданий с точностью до миллисекунд
  • Open source
  • Поддержка сопрограмм(Coroutines)

Возможные варианты использования:

  • Микросервисы
  • Игровые сервера
  • Интернет вещей
  • Живые системы общения
  • WEB API
  • Любые другие сервисы от которых требуется моментальный ответ/высокая скорость/асинхронное выполнение

Примеры кода можно увидеть на главной странице сайта. В разделе документации более подробная информация о всём функционале фреймворка.

Приступим к использованию


Ниже я опишу процесс написания несложного Websocket сервера для онлайн-чата и возможные при этом затруднения.

Перед тем как начать: Более подробная информация о классах swoole_websocket_server и swoole_server (Второй класс наследуется от первого).
Исходники самого чата.

Установка фреймворка
Linux users

#!/bin/bash
pecl install swoole

Mac users

# get a list of avaiable packages
brew install swoole
#!/bin/bash
brew install homebrew/php/php71-swoole


Для использования автокомплита в IDE предлагается использовать ide-helper

Минимальный шаблон Websocket-сервера:

<?php
$server = new swoole_websocket_server("127.0.0.1", 9502);

$server->on('open', function($server, $req) {
    echo "connection open: {$req->fd}\n";
});

$server->on('message', function($server, $frame) {
    echo "received message: {$frame->data}\n";
    $server->push($frame->fd, json_encode(["hello", "world"]));
});

$server->on('close', function($server, $fd) {
    echo "connection close: {$fd}\n";
});

$server->start();

$fd — идентификатор подключения.
Получить текущие подключения:

$server->connections;

Внутри $frame содержаться все отправленные данные. Вот пример пришедшего объекта в функцию onMessage:

Swoole\WebSocket\Frame Object
(   
    [fd] => 20
    [data] => {"type":"login","username":"new user"}
    [opcode] => 1
    [finish] => 1
)

Данные клиенту отправляются с помощью функции

Server::push($fd, $data, $opcode=null, $finish=null)

Подробнее про фреймы и opcodes на русском — на learn.javascript. Раздел «формат данных»

Максимально подробно про протокол Websocket — RFC

А как сохранять данные пришедшие на сервер?
Swoole представляет функционал для асинхронной работы с MySQL, Redis, файловый ввод-вывод

А также swoole_buffer, swoole_channel и swoole_table
Думаю различия понять не сложно по документации. Для хранения имён пользователей я выбрал swoole_table. Сами сообщения хранятся в MySQL.

Итак, инициализация таблицы имён пользователей:

        
$users_table = new swoole_table(131072);
$users_table->column('id', swoole_table::TYPE_INT, 5);
$users_table->column('username', swoole_table::TYPE_STRING, 64);
$users_table->create();

Заполнение данными происходит так:

$count = count($messages_table);

$dateTime = time();
$row = ['username' => $username, 'message' => $data->message, 'date_time' => $dateTime];
$messages_table->set($count, $row);

Для работы с MySQL я решил пока не использовать асинхронную модель, а обращаться стандартным способом, из вебсокет-сервера, через PDO

Обращение к базе
/**
     * @return Message[]
     */
    public function getAll()
    {
        $stmt = $this->pdo->query('SELECT * from messages');
        $messages = [];
        foreach ($stmt->fetchAll() as $row) {
            $messages[] = new Message( $row['username'], $row['message'], new \DateTime($row['date_time']) );
        }
        return $messages;
    }


Websocket сервер было решено оформить в виде класса, и стартовать его в конструкторе:

Конструктор
public function __construct()
    {
        $this->ws = new swoole_websocket_server('0.0.0.0', 9502);

        $this->ws->on('open', function ($ws, $request) {
            $this->onConnection($request);
        });
        $this->ws->on('message', function ($ws, $frame) {
            $this->onMessage($frame);
        });
        $this->ws->on('close', function ($ws, $id) {
            $this->onClose($id);
        });

        $this->ws->on('workerStart', function (swoole_websocket_server $ws) {
            $this->onWorkerStart($ws);
        });

        $this->ws->start();
    }


Возникшие проблемы:

  1. У пользователя подключенного к чату обрывается соединение через 60 секунд если не происходит обмена пакетами(т.е. пользователь ничего не отправлял и ничего не получал)
  2. Вебсервер теряет соединение с MySQL если долго не происходит никакого взаимодействия

Решение:

В обоих случая нужна реализация функции «пинг», которая будет постоянно каждые n секунд пинговать клиента в первом случае, и базу MySQL во втором.

Так как обе функции должны работать асинхронно, их нужно вызвать в дочерних процессах сервера.

Для этого их можно инициализировать при событии «workerStart». Мы уже определили его в конструкторе, и при этом событии уже вызывается метод $this->onWorkerStart:
Протокол Websocket поддерживает ping-pong из коробки. Ниже можно увидеть реализацию на Swoole.

onWorkerStart
private function onWorkerStart(swoole_websocket_server $ws)
    {
        $this->messagesRepository = new MessagesRepository();

        $ws->tick(self::PING_DELAY_MS, function () use ($ws) {
            foreach ($ws->connections as $id) {
                $ws->push($id, 'ping', WEBSOCKET_OPCODE_PING);
            }
        });
    }


Далее я реализовал простенькую функцию для пинга MySQL сервера каждые N секунд, используя swoole\Timer:

DatabaseHelper
Сам таймер запускается в initPdo если ещё не включен:

    /**
     * Init new Connection, and ping DB timer function
     */
    private static function initPdo()
    {
        if (self::$timerId === null || (!Timer::exists(self::$timerId))) {
            self::$timerId = Timer::tick(self::MySQL_PING_INTERVAL, function () {
                self::ping();
            });
        }

        self::$pdo = new PDO(self::DSN, DBConfig::USER, DBConfig::PASSWORD, self::OPT);
    }

    /**
     * Ping database to maintain the connection
     */
    private static function ping()
    {
        try {
            self::$pdo->query('SELECT 1');
        } catch (PDOException $e) {
            self::initPdo();
        }
    }


Основная часть работы заключалась в написании логики для добавления, сохранения, отправки сообщений(не сложнее обычного CRUD), а далее огромный простор для усовершенствований.

Пока что я привёл свой код к более-менее читаемому виду и объектно-ориентированному стилю, реализовал немного функционала:

— Вход по имени;

- Проверку что имя не занято
/**
     * @param string $username
     * @return bool
     */
    private function isUsernameCurrentlyTaken(string $username) {
        foreach ($this->usersRepository->getByIds($this->ws->connection_list()) as $user) {
            if ($user->getUsername() == $username) {
                return true;
            }
        }
        return false;
    }


- Ограничитель запросов для защиты от спама
<?php

namespace App\Helpers;

use Swoole\Channel;

class RequestLimiter
{
    /**
     * @var Channel
     */
    private $userIds;

    const MAX_RECORDS_COUNT = 10;

    const MAX_REQUESTS_BY_USER = 4;

    public function __construct() {
        $this->userIds = new Channel(1024 * 64);
    }

    /**
     * Check if there are too many requests from user
     *  and make a record of request from that user
     *
     * @param int $userId
     * @return bool
     */
    public function checkIsRequestAllowed(int $userId) {
        $requestsCount = $this->getRequestsCountByUser($userId);
        $this->addRecord($userId);
        if ($requestsCount >= self::MAX_REQUESTS_BY_USER) return false;
        return true;
    }

    /**
     * @param int $userId
     * @return int
     */
    private function getRequestsCountByUser(int $userId) {
        $channelRecordsCount = $this->userIds->stats()['queue_num'];
        $requestsCount = 0;

        for ($i = 0; $i < $channelRecordsCount; $i++) {
            $userIdFromChannel = $this->userIds->pop();
            $this->userIds->push($userIdFromChannel);
            if ($userIdFromChannel === $userId) {
                $requestsCount++;
            }
        }

        return $requestsCount;
    }

    /**
     * @param int $userId
     */
    private function addRecord(int $userId) {
        $recordsCount = $this->userIds->stats()['queue_num'];

        if ($recordsCount >= self::MAX_RECORDS_COUNT) {
            $this->userIds->pop();
        }

        $this->userIds->push($userId);
    }
}

P.S.: Да, проверка идёт по connection id. Возможно имеет смысл заменить его в данном случае, например, на IP адрес пользователя.

Ещё я не уверен что в данной ситуации лучше всего подходил именно swoole_channel. Думаю позже пересмотреть этот момент.

— Простенькую защиту от XSS используя ezyang/htmlpurifier

- Простенький спам-фильтр
С возможностью в дальнейшем добавить дополнительные проверки.

<?php

namespace App\Helpers;

class SpamFilter
{
    /**
     * @var string[] errors
     */
    private $errors = [];

    /**
     * @param string $text
     * @return bool
     */
    public function checkIsMessageTextCorrect(string $text) {
        $isCorrect = true;
        if (empty(trim($text))) {
            $this->errors[] = 'Empty message text';
            $isCorrect = false;
        }
        return $isCorrect;
    }

    /**
     * @return string[] errors
     */
    public function getErrors(): array {
        return $this->errors;
    }
}


Frontend у чата пока что весьма сырой, т.к. меня больше привлекает backend, но когда будет больше времени я постараюсь сделать его поприятнее.

Где брать информацию, узнавать новости о фреймворке?


  • Английский официальный сайт — полезные ссылки, актуальная документация, немного комментариев от пользователей
  • Twitter — актуальные новости, полезные ссылки, интересные статьи
  • Issue tracker(Github) — баги, вопросы, общение с создателями фреймворка. Отвечают очень шустро(на мою issue с вопросом ответили за пару часов, помогли с реализацией pingloop).
  • Закрытые issues — так же советую. Большая база вопросов от пользователей и ответы от создателей фремворка.
  • Тесты, написанные разработчиками — практически на каждый модуль из документации есть тесты написанные на PHP, показывающие варианты использования.
  • Китайская wiki фреймворка — вся информация что и в английской, но значительно больше комментариев от пользователей (гугл переводчик в помощь).

API documentation — описание некоторых классов и функций фреймворка в довольно удобном виде.

Резюме


Мне кажется, что Swoole очень активно развивался последний год, вышел из стадии когда его можно было назвать «сырым», и теперь вполне составляет конкуренцию использованию node.js/go с точки зрения асинхронного программирования и реализации сетевых протоколов.

Буду рад услышать различные мнения по теме и отзывы от тех кто уже имеет опыт использования Swoole

Пообщаться в описанном чатике можно по ссылке
Исходники доступны на Github.
Поделиться публикацией

Похожие публикации

Комментарии 35
    0
    Больше трёх сообщений чатик Ваш не даёт отправить. НО! Перезагрузив страницу по новой логинимся и опять отправляем. Привязку к сессии сделать было бы неплохо.
      0
      Да, я знаю об этом. Пока что проверяю просто по ID подключения.
      В принципе если кому-то очень хочется нафлудить, то ему и сессия не помешает, думаю чуть позже сделаю спам фильтр построже
      +1

      С PDO есть проблема в том, что он синхронный. Т.е. пока запрос не выполнится все клиенты swoole ждут его завершения.
      В swoole 4.1 добавили какую-то штуку по заворачиванию PDO и проч в асинхронную обертку (см https://pecl.php.net/package-changelog.php?package=swoole), но я не ковырял)

        0
        Хм… Я думал что суть их асинхронного подключения БД в возможности продолжить выполнять код в текущем воркере параллельно с запросом, а другие клиенты собственно в другом процессе выполняют свои запросы. Займусь этим вопросом.
          0
          upd: Запустил через PDO и корутины долгие запросы к MySQL, проследил за выполняющимися процессами.
          Вы правы насчёт синхронности PDO. Впрочем, в текущих условиях это не принипиально

          Когда я писал это не смог по быстрому осилить установку mysqlnd на моей системе
          –7

          Асинхронные серверы на подходящих для того языках типа ноды или го — это для слабаков!
          Только пхп, только гланды через назад!

            +1
            Осмелюсь спросить — что для вас «подходящий язык»?
              +4

              подозреваю, что человек живет в мире ~php5

                0
                справедливости ради — node или go или python с точки зрения экосистемы намного больше подходят для таких вещей. Ну вот прям… сильно.

                Проблема повторюсь в экосистеме а не в языке. Все же асинхронщина на php пока занимает умы подавляющего меньшинства. Да и нюансов больше.
              0
              Ну в статье описывается инструмент, прямо предназначенный для написания асинхронных серверов, и инструмент, кстати, не на PHP. Так что не вижу никаких проблем.
              +2
              Я пробовал Swoole год назад. Из того что помню:
              Пока делал специфичный чат, вышла новая версия, вроде 2.2. Но новая версия не смогла собраться со всеми нужными мне пакетами на убунту 16.04 (вебсокеты не собирались). Не работали корутины.

              Делал просто сервер, данные хранил в swoole_table.

              Еще была ошибка, что не мог пушануть ответ, из-за каких то вложеностей вызовов функций. Гуглил, такое бывает, решение которое предлагали китайцы(основные разработчики) прислать им дебаг инфу на Си.
              Пришлось переписать проще, чтобы логика была в функции onMessage сразу.

              Создалось впечатление, что сырой продукт еще. И пожалел, что не стал использовать ReactPHP. Более привычно для ПХПшника.
              В общем работает, соединения не рвет, как у вас. Но у меня другая версия была.
              Но может просто я не понял swoole :)
                0
                Уже v4.1.0: )
                В в новой версии я таких багов не встречал, надеюсь что это не только моё везение.
                Конечно, не всё идеально
                Но серьёзных косяков вроде нет, а если что авторы всегда очень шустро отвечают, и стараются фиксить найденные баги.
                0

                Можно подойти к проблеме с другой стороны и заниматься многопоточностью над ПХП: https://github.com/spiral/roadrunner

                  0
                  Нагрузочное тестирование не проводили?
                    0
                    Лично я нет, но в интернете и в т.ч. у них на сайте(или на гитхабе, не помню точно), выкладывались результаты тестирования и используемый код.
                    Вот нашёл например: www.swoole.co.uk/benchmark, правда тестировалась старая версия
                    0
                    По прежнему считаю PHP самым удачным и лучшим интерпретатором. Каноничный C-подобный синтаксис (без всяких вот этих ваших «удобочитаемых» ЯП), а так же максимально приближенное к реальности ООП.
                      +1
                      Не забывайте что язык — всего лишь инструмент для достижения поставленных целей, и может меняться в зависимости от задач: )
                        0
                        разумеется, но в данном контексте, я имел ввиду вэб (именно серверная часть)
                        0
                        > а так же максимально приближенное к реальности ООП.

                        значит вы плохо понимаете что такое это самое ООП. В этом плане наиболее «приближен к реальности» Erlang. А если под ООП вы классы подразумеваете — без inner классов хотя бы сложно структурировать адекватно, все время приходится на компромисы какие-то идти.

                        Ну и в целом PHP как язык — очень плох. Прям очень (чаще всего выражается это в полумерах, принятых в языке). И если вам так не кажется — то либо мы говорим о PHP как о платформе (с этой точки зрения все прекрасно) либо у вас специфичные вкусы.

                        На сегодняшний день у php достаточно конкурентов, и аргумент что разработчиков найти проще уже не очень правда… во всяком случае адекватных разработчиков найти не проще чем на любом другом языке.
                          +1
                          1. ООП в PHP — имеется ввиду относительно других интерпретаторов, нацеленных на вэб-разработку
                          2. Erlang имеет далеко не самый приятный стиль программирования (об «удобочитаемом» синтаксисе — я молчу), да и придуман он как раз для других задач
                          3. Есть вещи, которые уже устаканились временем:
                          — хочешь приложение для эпловской системы — используешь Swift
                          — хочешь приложение для виндовой системы — используешь C#
                          — хочешь приложение для вэба — используешь для клиента — JS, для сервера — PHP
                          — хочешь сделать что-то кроссплатформенное — используешь Java
                          В большинстве случаев — этого хватает с головой, если присутствуют специфические задачи, или «вкусы», вот только тогда, либо прибегают к использованию других ЯП, либо создают свой новый ЯП.

                          Относительно высосаных из пальца аргументов, есть такое понятие — брэнд(ы), они приходят и уходят (это я об ваших конкурентах, если что), остается лишь рабочее средство, проверенное временем. (сори за тавтологию).

                          В общем, мой посыл в том, что есть уже всем привычное ООП (java-like) c реально понятным С-подобным синтаксисом, которое работает и не приносит такой большой боли и страдания (относительно НЕ специфических задач и вкусов).
                            0
                            1. я к тому что я понятия не имею что вы под ООП имеете ввиду.
                            2. Есть Elixir, у него синтаксис поприятнее. Что до "других задач" — ну вот то куда люди свулле впихивают как раз таки "те самые другие задачи".
                            3. Swift можно использовать хоть для бэкэнд разработки хоть для фронтэнда (webassembly). Это ваши стереотипы. Так же как и Kotlin native можно юзать для написания экстеншенов для php. C# так же вполне себе юзабелен для кросплатформенной разработки нынче. Для вэба — опять же выбор сильно больше, ну и опять же — подождем годика три пока webassembly наберет популярность. А так уже сегодня многие используют различные трансляторы в js.

                            Как там говорится, прогресс движется в сторону интеропа языков и это хорошо.


                            Относительно высосаных из пальца аргументов

                            еще раз, я против php как платформы ничего не имею, использую его на протяжении 10-ти лет. Но повторюсь, язык убогий.


                            уже всем привычное ООП (java-like)

                            посмотрите как в той же джаве можно красиво билдеры описать и грустите что подобного в php не будет. Нет, ну может быть вот это протащат и я тогда буду меньше ругаться, но…


                            А пока все эти "самый лучший интерпритатор" и прочие восхваления языка лишь вред ему несут.

                              0
                              Fesor
                              Ну и в целом PHP как язык — очень плох. Прям очень… И если вам так не кажется — то… у вас специфичные вкусы.
                              Вы называете большинство веб-разработчиков — ''извращенцами", только потому что они имеют отличный от вашего вкус? При этом вы сами используете php на протяжении 10-ти лет… Вы извращенец или мазохист?
                              Лично меня php устраивает, что-то нравится, а что-то нет, но по большей части нравится. Тоже самое и с другими языками. Кучу людей не устраивает java, кого-то golang, но никто в своём уме не пишет, что у тех кому они нравятся — «специфичные вкусы». Язык программирования — не 100 баксов, чтобы нравиться всем. К тому же подход к выбору языка «нравится/не нравится» не очень объективный, ведь это особенность работы нашего мозга — ему нравится знакомое.
                              Именно по этому, когда стоит задача «прикрутить вебсокеты», чаще берут решение, которое позволяет это сделать на знакомом языке и для php-разработчика самые частые решения — это swoole, workerman и т.д., потом node.js, а уже только затем golang, erlang, python и т.д.
                                0
                                > Вы извращенец или мазохист?

                                вы фразу видимо не дочитали. PHP отличная платформа со своими изюминками (вроде умирающей модели выполнения, алицетворяющей феникса). Вот эта самая платформа и привлекает людей. Платформа, а не язык.

                                В возможно вы вовсе и не про язык а про интерпритатор говорили. В таком случае смысл вашего комментария для меня остается загадкой.
                                  +1
                                  Платформа -> Архитектура -> Язык -> Интерпретатор -> Вкусы..., мб еще на атомы расщеплять будем???
                                  Что имелось ввиду: PHP имеет (относительно) всем привычный C-подобный синтаксис и отличное ООП. Он создан конкретно для вэба, и в целом подходит для подавляющего большинства задач (серверная часть).
                                    0
                                    и отличное ООП

                                    Как вы сделали такой вывод?


                                    всем привычный C-подобный синтаксис

                                    как и половина других языков программирования.


                                    Он создан конкретно для вэба

                                    А еще он создавался как шаблонизатор для Си. Это тоже будем вспоминать?


                                    и в целом подходит для подавляющего большинства задач

                                    Не спорю, и он прекрасно с ними справляется. Как платформа. Но язык довольно неконсистентный, и в нем масса крайне сомнительных решений.

                                      –1
                                      Но язык довольно неконсистентный, и в нем масса крайне сомнительных решений.
                                      Назовите мне язык из топ5, в котором нет таких проблем?
                                      На ЯП либо жалуются либо им не пользуются. Большинство всех ваших претензий подходят к любому другому языку.
                        +1
                        В вашей картинке есть сравнение swoole с чем угодно кроме главного конкурента workerman.
                        Во время участия в highloadcup, я сделал такое сравнение и в синтетическом тесте swoole оказался быстрее чем workerman менее чем на 10%, а в реальном разница была пару процентов.
                        При этом swoole_table жрал памяти в 20 раз больше чем лучшее решение.
                        В общем для конкурса я оставил swoole, потому что там была важна каждая микросекунда. В реальности же я использую workerman, потому что:
                        • у него лучше документация (к тому же всегда можно прочесть код в php-исходниках, чтобы разобраться),
                        • доработка под себя (средний php-разработчик может дописать php-библиотеку, а сишную — нет)
                        • более быстрое развитие (любой php-разработчик может отправить пулл-реквест в воркерман, а в случае swoole приходится ждать, когда его разработчики напишут/не напишут то что тебе требуется)

                        были и другие мелочи, которые приходилось терпеть, то что можно было бы исправить в workerman за 5 минут.
                          0
                          Спасибо за развернутый комментарий. Статью вашу я конечно же читал ещё когда искал информацию про Swoole, и сейчас только понял что та issue на Github «Why is swoole table so expensive» была от вас).

                          В принципе данные, если они должны лежать в памяти можно писать в Redis. А на постоянное хранение — в MySQL.

                          А можете рассказать, каких мелочей не хватало в Swoole?

                          Думаю займусь и изучением WorkerMan ради интереса.
                            0
                            На вскидку, могу вспомнить нотисы, которые вылезали в консоли, если вебсокет закрывается не кодом на js, а просто закрытием вкладки (т.е. ситуация достаточно стандартная) и подобные мелочи.
                            Было два режима SWOOLE_BASE и SWOOLE_TASK (дефолтный), внятного описания не было даже на китайском.
                            Были какие-то проблемы с воркерами. То что мне нужно было в альфе и я ловил ошибки.

                            В любом случае, большое спасибо за статью. Это первая статья про swoole на хабре. Я сам о нём узнал буквально полтора-два года назад, хотя вроде как в теме «вебсокеты на пхп» я не чужой. Swoole / workerman достойно справляются со своими задачами и будут с ними справляться до выхода php8, где всё это обещают уже из коробки.
                              +1
                              Да, про документацию мне конечно известно. Проблем с нотисами при отключении клиента никаких не возникало.
                              А мотивация для написания данной статьи мне пришла как раз после вашего цикла статей о Вебсокетах )
                          0
                          Откуда КДПВ? Удивляет очень плохой результат Phalcon'а, а ведь он тоже написан на Си и по многим бенчмаркам он показывает большую производительность, чем, к примеру, фреймворки написанные на чистом PHP.
                          Хотелось бы изучить детально методы которые использовались для сравнения.
                            +1
                              +1
                              EvgeniiR
                              Спасибо, теперь понятно почему workerman показал в этом тесте такие низкие результаты. В докер-контейнере не установлен libevent.

                              megasween
                              Удивляет очень плохой результат Phalcon'а
                              Собственно Phalcon на графике выше yii2 и kohana, но логично медленнее чем swoole, ведь Phalcon — это целое приложение, а swoole — всего один файл.
                                0
                                Собственно Phalcon на графике выше yii2 и kohana, но логично медленнее чем swoole, ведь Phalcon — это целое приложение, а swoole — всего один файл.

                                Согласен, теперь посмотрев внимательно на то, что из себя представляет тест, а так же на результаты других тестов, успокоился :)
                              +1
                              Phalcon призван уменьшить оверхэд на бутстраппинг фреймворка, однако этот оверхэд все же есть. Свулле же это полноценный application server, а потому такие штуки как «отдать json» для него фигня. Из вариантов не требующих «переписи» лично мне нравится roadrunner. Будет не так круто как со свулле но я предпочел бы писать подобное не на php.

                              А вот почему такая огромная разница с тем же amp (разве что парсинг http запросов силами php) — это для меня загадка.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое