@gitdev

Поддерживает ли PHP асинхронность на уровне ядра языка программрования?

Поддерживает ли PHP асинхронность из коробки, если да - то как и что почитать на эту тему?
  • Вопрос задан
  • 225 просмотров
Пригласить эксперта
Ответы на вопрос 3
@rPman
из коробки в php есть асинхронные методы работы с сокетами, метод socket_select позволяет создать event loop и вести асинхронную коммуникацию

так же библиотека curl позволяет вести загрузку в фоновом режиме с помощью curl_multi_...

используя штатные механизмы языка созданы библиотеки по типу ReactPHP с помощью которых можно создавать событийно-ориентированные приложения, например асинхронный websocket и http сервер в одном приложении. Если сравнивать с nodejs, где асинхронность 'из каропки' то реализация на php чуть медленнее но так каксам язык в большинстве случаев работает быстрее, в некоторых случаях код будет работать быстрее (например я писал простейший веб сервис, работающий со сжатыми gzip файлами 'построчно', так вот на nodejs было сильно медленнее, но сам event loop там быстрее)

p.s. чтобы nodejs по скорости был сравним с php приходится осторожно выбирать какими методами пользоваться, например штатные объекты и массивы там медленнее чем класс Map
Ответ написан
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Чтобы сделать пример асинхронки на коленке, не вдаваясь в детали, нужно завернуть действие в генератор и перед каждой строкой кода писать "yield <строка кода>", чтобы код останавливался и передавал управление наружу. В этом случае собрав пачку генераторов и используя форич чтобы в КАЖДОМ ШАГЕ двигать КАЖДЫЙ ГЕНЕРАТОР на один шаг вперед - можно получить асинхронное выполнение.

Если чуть глубже то yield на самом деле стоит писать перед теми операциями, что делаются долго, но при этом не то, что они тяжелые, а они предполагают ожидание чего-то. Например, отсылка почты сама по себе происходит быстро, а вот пока подключишься к серверу - это висим. Вот эти самые нетяжелые но долгие операции имеют время простоя, которое можно куда-то еще применить, пока ждем, если написать свою функцию mail(), которая открывает соединение и шлет что-то серверу, то есть по тому самому SOLID не сразу отсылает емейл а делает это в пару этапов, между которыми будут запускаться "шаги" из других генераторов.

Но оно не будет параллельное в полном смысле (одновременно делаться не будет, просто будет более грамотное управление простоями).

А вот блокирующие функции, например, функция sleep() она по умолчанию блокирующая, то есть вызвав её мы будем висеть сколько-то секунд. Она блокирующая не потому, что она "родилась такой", а потому что в ней внутри не сделаны передача управления наружу в каждом тике. Поэтому пишут так как еще в яваскрипте показывали - ставят таймер на 1 секунду к примеру (а лучше на так называемое "время тика"), и в каждом шаге проверяют - "столько-то секунд с момента запуска таймера прошло уже?" и если прошло то двигают генератор дальше, если нет - продолжают ждать.

Это создает некую иллюзию асинхронного кода, но это не совсем то же самое что сделать pcntl_fork(), который в конечном итоге будет делать действительно в двух разных процессах (программах) и ему будет люто наплевать что делается в соседней. А затем родитель, породивший все форки просто вешает ожидалку всех детей до состояния "пока закончилось", тем самым получается нечто вроде Promise.all(tasks).

Как итог pcntl_fork() - это переброс ответственности за опрос потомков на саму прогу php и на железо компьютера вместо кода, написанного на php, где каждая команда под капотом будет выполнять множество машинных вызовов, протупливать и так далее. Когда железо следит за этим получается НАМНОГО быстрее, задействуется больше ресурсов компьютера и т.д. Но в действительности там тоже нет прям вот "одновременного" с точки зрения момента времени, но есть "пока есть свободный исполнитель возьми это на себя", что действительно является одновременностью с точки зрения промежутка времени.

Есть и прикольная новость. То что в винде до сих пор этого нет (хотя помнится вместе с PowerShell уже как-то вкрутили через три села и корчи), то это значит что если вы подымаете эту тему, то ваш уровень примерно "майкрософт". Можете запихнуть это в глотку рекрутеру, который будет говорить что вы "не имеете опыта в высоконагруженных распределенных системах" и улыбаться тому, что она едва умеет в эксель.

====

Немножко практики - "когда без асинхронки не обойтись". Еще пару лет назад я был уверен что в пхп асинхронка не нужна вообще. Ну дескать - язык такой, нет здесь асинхронных задач.
А вот и нет. Просто асинхронность у пхп разработчиков берет на себя Nginx + PHP-FPM или Апач. Это его задача на каждый запрос подымать процесс и делать его отдельно.
Когда система ТЯЖЕЛЕЕТ и не может справляться с поставленными задачами потому что Nginx имеет время ожидания, и скрипты запущенные из апача висящие в браузере (например) часами - это ересь и бред, или когда буквально не хватает ресурсов одного компьютера и всё глючит, а нагрузка шкалит под 90%, задаешься тем, что нужно МАСШТАБИРОВАТЬ приложение. Это значит что операции требующие много времени нужно выбросить на другую машину. Сразу такой "как же это сделать". Начинаешь читать про БРОКЕРЫ СООБЩЕНИЙ. Редисы (rpush, lmove), Раббиты (ampq, тормознутый как старое пердало), Кафки (event sourcing из коробки на компах с 384гб оперативы - у вас такого нет), Натсы (к которым не найдешь пхпшной обертки нормальной). И тут выясняется следующее. Что когда из пыхи ты стрельнул сообщением в брокер, а кто-то, кто на него подписался сообщение получил, то он делает его СИНХРОННО, одно за другим. И нет там апача который заботливо на каждое сообщение подымает для тебя новый процесс. И вот тут ты задумываешься как же сделать так, чтобы пришедшие сообщения делались не одно за одним, а сразу десяток. И понимаешь - как хорошо, когда асинхронка уже есть, приручаешь pcntl_fork() и делаешь ручками. В этот момент происходит отсев разработчиков на "пыха дерьмо" и "пыха может всё". Вот первые уходят в GoLang или долбятся с NodeJs и прикручивают, а другие понимают что в пыхе есть другие преимущества, потерять которые - дороже.

Кое-что про Pthreads и почему его "забыли". Его не забыли. Просто pthreads подымал разные задачи от начала до конца. То есть в каждом процессе требовалось произвести инициализацию того же фреймворка например. Это дорого и тяжело. В отличие от форка, который в нужный момент просто отпочковывается в другую задачу сохраняя всё, что уже было сделано. Это лучше, чем стартовать целые скрипты заново.
Ответ написан
Mecitan
@Mecitan
Уверенный пользователь клавиатуры
Есть такие штуки, генераторы, это почти как асихнронность. :D
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы