В этом выпуске Антон Шабовта, человек, который собаку съел на асинхронном программировании в PHP, рассказывает текущее положение дел в экосистеме, кратко и ёмко про ReactPHP, PHP-PM, swoole, RoadRunner, amphp, ext-async и про свой доклад на PHP Russia 2019.
- https://phprussia.ru/2019/abstracts/5013
- https://reactphp.org
- https://github.com/php-pm/php-pm
- https://www.swoole.co.uk
- https://roadrunner.dev
- https://amphp.org
- https://github.com/concurrent-php/ext-async
- https://github.com/phpinnacle/ — библиотеки от Антона по асинхронному PHP
Антон, привет! Расскажи нам, кто ты, чем ты занимаешься?
Всем привет, меня зовут Антон Шабовта, PHP-разработчик и не только. Последние несколько лет я активно занимаюсь разработкой асинхронных приложений на PHP. В частности, я пишу библиотеки и драйвера, которых мне не хватает в асинхронном мире.
Начнём с основ. Дай краткое определение, что такое асинхронное программирование, что мы под этим понимаем?
С определениями в асинхронном мире всё очень сложно. Есть какие-то формальные штуки и какие-то формальные определения из Википедии, которые говорят нам приблизительно ничего. Но когда мы говорим за асинхронный PHP,то чаще всего мы подразумеваем какой-то асинхронный I/O(ввод-вывод) также, например, как NodeJS.
Сейчас есть некоторое количество библиотек, которое позволяет так или иначе реализовать механизм. Асинхронных вызовов встроенных в PHPпока нету, но мы можем их эмулировать различными методами.
Для себя лично я вижу два определения, что такое асинхронное программирование. Определение первое: это когда наши вызовы и работа с I/O не блокирует поток выполнения. Не блокирует текущую рутину. Второе определение, оно попроще: это когда у нас результат операции доступен не сразу, а через какое-то время, либо не будет доступен вообще.
Мы традиционно уже, пару десятков лет писали сайты различного уровня сложности на PHP без асинхронного программирования. Какие плюсы могло бы дать асинхронное программирование, если мы возьмём какие-то библиотеки сейчас, или если в будущем поддержка появится непосредственно в ядре PHP?
Давайте вспомним историю. Когда-то лет 10 назад у нас был классический LAMP-стек: Linux, Apache, MySQL, PHP. PHPработал тогда в режиме mod_php, что было достаточно небыстро. Но мир менялся и скорость становилась всё более и более критически-важным показателем. У нас появился такой инструмент, как PHP-FPM, который значительно ускорил обработку запросов в PHP, позволил таким сайтам, как Badoo, ещё долго-долго его использовать, а не срочно переписывать на что-то побыстрее. Сейчас скорость требуется всё больше и больше, и текущих инструментов уже не хватает, поэтому идея по использованию асинхронного программирования – это одна из возможностей ускорить обработку запросов и более оптимально утилизировать ресурсы.
Я слышал про такие библиотеки: ReactPHP, swoole, RoadRunner, PHP-PM и ещё некоторые. Частенько они проскакивают в знаменитом PHP-дайджесте на Хабрев разделе «Асинхронный PHP». Но, мне кажется, тут иногда есть некоторая путаница, какие библиотеки действительно занимаются чем-то связанным с асинхронным программированием, а что из этого относится к серверам приложений. Можешь ли ты нам прояснить?
Давайте разберёмся по порядочку, и опять же пойдём от истории.
Первая библиотека, которая позволила писать действительно асинхронные приложения на PHP- это был ReactPHP, который утилизирует концепцию Event loop’aдля обработки сигналов от ОС и представления каких-то результатов для асинхронных операций. Впоследствии для него был написан сервер приложений на самом PHP и называется он PHP-PM. Он работает поверх ReactPHP и контролирует запросы, позволяет нам как-то проще обрабатывать входящие на сервер подключения, и заботится о том, если у нас приложение ReactPHP упадёт, чтобы не умерло полностью всё. То есть PHP-PM, скажем так, супервизор для http-запросов ReactPHP.
Две следующие библиотеки тесно связаны с Go-миром.
Swoole подошёл к этому как к расширению для PHP, и они пытаются из расширения эмулировать PHPработу похожую на Go. То есть они подменяют все вызовы и позволяют работать с какими-то с виду синхронными операциями так как мы работает с асинхронными. Это очень хорошая концепция, она интересная, но для меня Swoole – это, так скажем, непознанный мир, с ним очень сложно в плане документации, библиотека китайская, большинство issue и документации только на китайском, и с этим естественно есть сложности. Если какие-то нюансы возникают в процессе написания приложения на Swoole, найти нужную информацию достаточно сложно.
Теперь переходим к RoadRunner’у. RoadRunner – это разработка Антона Титова. Это попытка сделать первые приложения для PHP на Go. Он имеет малое отношение именно к асинхронной работе, так как внутри весь запрос в RoadRunner’eне является полностью асинхронным. На данный момент скомбинировать подходы и, например, использовать ReactPHP внутри RoadRunner приложений не получится, так как мы будем перезатирать текущий стек, будет исчезать текущая область видимости. Если в RoadRunner мы получаем все наши знакомые PSR-7 request, как-то его обрабатываем, то прокинуть это request в ReactPHP или amphp не получится. И потом не понятно, кому возвращать ответ. Мы с Антоном уже обсудили этот вопрос, и я думаю, что в ближайшем будущем такая возможность всё-таки в RoadRunner появится.
Ещё одна библиотека, которую ты не упомянул, но о которой я буду больше всего говорить – это amphp. Это развитие идеи ReactPHP. Они используют тот же Event loop, но в отличии от ReactPHP, они делают одну замечательную штуку, которая называется корутиной. Делают они поверх генератора и это позволяет писать код, который выглядит как асинхронный, за одним исключением, у нас появляется слово yield перед асинхронными вызовами. Это намного упрощает разработку, у нас исчезает такое понятие, знакомое всем с JS-мира, как callback hell. Сейчас, наверное, это самый актуальный фреймворк для разработки асинхронных приложений на PHP.
Вопрос: если я возьму PHP-PM сервер приложений, внутри у нас ReactPHP, и туда запихну приложение на старом-добром Symfony – оно от этого ведь не становится асинхронным, правильно я понимаю? Мне нужно будет переписать все вызовы к MySQL, все вызовы по работе с файлами на асинхронные аналоги?
Да, конечно. Само приложение не станет асинхронным каким-то магическим образом, так как работа с асинхронными вызовами немножко другая. Но просто обернув Symfony или Lavarel приложенияв ReactPHP мы получим приблизительно тоже, что делает RoadRunner. То есть мы получим асинхронный код запросов и отправку ответов, но внутри у нас всё останется синхронным. То есть мы сэкономим только на Bootstrap’e приложений. Bootstrap, на самом деле для таких фреймворков как Symfony или Lavarel – это значительная часть запросов, процентов 30, а может быть и 40.
А что насчёт Swoole? Ты сказал, что он внутри подменяет вызовы. Значит ли это, что Symfony приложения, которые используют обычные php функции, какой-нибудь file_put_contents(), станет вдруг асинхронным, потому что file_put_contents() подменён в самом Swoole на асинхронный аналог?
Оно подменяет, но нам надо оборачивать любой такой вызов в отдельную функцию, которую Swoole сможет перехватить внутри своего расширения и уже там вызвать асинхронно. Насколько я сейчас вижу, они только экспериментируют сейчас с этим и какого-то однозначного решения до конца пока у них нет.
То есть дописать чуть-чуть код, или переписать код всё равно придётся, что ни бери?
Это основная беда асинхронного программирования, что код к нему надо будет писать с нуля. Вторая вытекающая из этого беда, что мы не сможем использовать любые встроенные и привычные для понимания для php разработчика штуки, такие как PDO, как redis-connection’ы. Нам надо будет использовать асинхронные аналоги, которые написаны на самом PHP и работают с бинарным протоколом или, например, с файлами в асинхронной манере.
А что за расширение еxt-async?
Оно сейчас активно развивается. Релизы выходят достаточно часто. Ext-async – это совместная инициатива всех заинтересованных лиц в асинхронной разработке на PHP. Оно по сути унифицирует работу с какими-то асинхронными примитивами. Если тот же ReactPHP или amphp под капотом могут использовать различные низкоуровневые драйверы, такие как libuv, работы с асинхронными вызовами, то ext-async скрывает определение текущего драйвера в системе подходящего и предоставляет наружу уже готовые примитивы а-ля promise, defer, task и так далее. Следующая версия ReactPHP, кстати, будет уже использовать ext-async под капотом.
А что слышно про ядро PHP? Были какие-то спекуляции на тему, может быть асинхронное программирование появится в ядре?
Все спекуляции начались с письма Зеева Сураски — открытого письма к PHP-комьюнити, о том куда и как будет в дальнейшем развиваться PHP. В письме был очень позитивный посыл и он упоминал много функций, которых все ждут в PHP, в том числе я. Например, я конечно жду асинхронности в ядре.
Но на данный момент у меня большие сомнения насчёт того, что это действительно войдёт в PHP 8, так как это огромный пласт работы, это огромные изменения, которые затрагивают и обратную совместимость, и пока я думаю, что всё-таки мир не совсем готов к таким изменениям. Но хочется верить, и если ребята найдут какое-то действительно красивое решение, для того, чтобы внедрить поддержку того же Event Loop’aна уровне ядра, это будет действительно очень круто. Возможно, нас ждёт некоторые разделение, как это произошло в Python-мире, например, где async/await на Python 3 работает на уровне самого интерпретатора, а в Python 2 он сделан поверх, так же как он сделан у нас сейчас в amphp.
Ты будешь выступать на PHP Russia 2019 с темой про асинхронное программирование. О чём твой доклад, что ты хочешь рассказать?
Да, я буду выступать, за что большое спасибо, что меня приняли в такую глобальную конференцию. Я действительно очень рад этому. Буду рассказывать про асинхронный PHP, про какие-то основы, постараюсь дать понимание процессов, которые за этим стоят, постараюсь объяснить, что это всё не так уж сложно, и это действительно можно использовать уже сейчас и иметь от этого большой профит. А чего не будет в докладе? В докладе не будет каких-то готовых решений. Он скорее направлен на juniorи middle-разработчиков, которые, когда встречают какие-то концепции а-ля promise, defer, корутины в PHP, им сложно с этим разобраться и сложно понять, что же действительно происходит под капотом. Я постараюсь всё это осветить, показать на примерах и, надеюсь, что это как-то поможет PHP-комьюнити быстрее прийти к использованию асинхронных решений в своих проектах.
Спасибо тебе за твою работу, просветительскую в том числе! А что лично ты хотел бы послушать и посмотреть на конференции? Что тебя интересует?
Конечно же, это два топ-спикера из Core PHP команды: Никита Попов и Дмитрий Стогов. Их доклады, обязательны, я считаю, к посещению, потому что они позволят лучше узнать инструмент, с которым мы работает каждый день. Чем лучше мы знаем инструмент, тем лучше мы его можем применять, и это действительно очень круто.
Ещё я хотел бы выделить доклад Антона Титова про RoadRunner, так как это бурнообсуждаемая и активная тема в PHP мире, интересно кто и как его использует. На самом деле, ребята делают очень крутую штуку, взяли лучшее из Go-мира, и из PHP-мира и сумели это соединить.
Да за этим будущее: брать лучшее из всех миров.
К этому нас подталкивает, собственно, всё комьюнити уже последние несколько лет. У нас с каждого утюга слышится про микросервисы, kubernetes, dockerи другие инструменты, которые позволяют нам использовать те технологии, которые нам хочется и объединять их между собой.
Источник: 5minphp.ru