Асинхронное выполнение PHP

Игорь Грегорченко

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

Выбор асинхронного решения всегда нетривиален, особенно в случае выполнения PHP.

PHP-FPM fastcgi_finish_request()

Если в качестве веб-сервера используется Nginx, то к вашим услугам отличный менеджер процессов FastCGI (FPM).

К примеру, отправка почты в асинхронном режиме будет выглядеть так:


$to = $_POST['email'];

if ( $to )

{

echo ‘Подтверждение отправлено на почту’;

**fastcgi_finish_request();

mail($to, ‘Подтверждение’, ‘Это ваш ящик?’);**

}

else

{

echo ‘Введены не все данные’;

}

## После вызова fastcgi_finish_request() посетитель сразу увидит ответ от сервера

Больше настроек и примеров в материале Асинхронность в PHP и FPM.

Неблокирующий режим потока

По умолчанию сокет открывается в блокирующем режиме, то есть дожидается полного соединения, прежде чем возвратить значение. Так что для выполнения асинхронных вызовов пригодится дополнительная директива socket_set_nonblock:

function multiHTTP ($urlArr) {

$sockets = Array(); // массив сокетов

$urlInfo = Array();

$retDone = Array();

$retData = Array();

$errno = Array();

$errstr = Array();

for ($x=0;$x<count($urlArr);$x++) {

$urlInfo[$x] = parse_url($urlArr[$x]);

$urlInfo[$x][port] = ($urlInfo[$x][port]) ? $urlInfo[$x][port] : 80;

$urlInfo[$x][path] = ($urlInfo[$x][path]) ? $urlInfo[$x][path] : “/”;

$sockets[$x] = fsockopen($urlInfo[$x][host], $urlInfo[$x][port],

$errno[$x], $errstr[$x], 30);

**socket_set_nonblock($sockets[$x]); **

$query = ($urlInfo[$x][query]) ? “?” . $urlInfo[$x][query] : “”;

fputs($sockets[$x],”GET ” . $urlInfo[$x][path] . “$query HTTP/1.0rnHost: ” .

$urlInfo[$x][host] . “rnrn”);

}

// чтение данных

$done = false;

while (!$done) {

for ($x=0; $x < count($urlArr);$x++) {
if (!feof($sockets[$x])) {
if ($retData[$x]) {
$retData[$x] .= fgets($sockets[$x],128);
} else {
$retData[$x] = fgets($sockets[$x],128);
}
} else {
$retDone[$x] = 1;
}
}
$done = (array_sum($retDone) == count($urlArr));
}
return $retData;
}
?>
## Функция подключается к массиву URL-ов в асинхронном режиме и возвращает массив результатов

Также можно задействовать неблокирующий режим потока. Для этого используется функция stream_set_blocking . К примеру в неблокирующем режиме вызов fgets() будет сразу возвращаться, не дожидаясь доступности всех данных на потоке.

Небольшой пример использования:

function call_url($url) {

$fp = fopen($url, ‘r’);

**stream_set_blocking($fp, 0);**

$data = fread($fp, 8192);

fclose($fp);

return strlen($data);

}
## Вызов url и моментальный возврат ответа, удобно для запуска других скриптов

Exec и cURL

Для запуска фоновых процессов curl можно использовать exec. Простой пример выполнения будет выглядеть так:


## Запрос выполняется почти моментально (50 мс), а в фоне запускается нужный длинный скрипт

Процессы curl также можно запустить из под командной оболочки:

curl -X POST -H 'Content-Type: application/json'

-d ‘{“batch”:[{“userId”:”some_user”,”event”:”PHP Fork Event”,”timestamp”:”2016-05-16T14:34:50-08:00″,”context”:{“library”:”analytics-php”},”action”:”track”}]}’

‘https://api.somesite.com/import’ > /dev/null 2>&1 &

## Запуск и раздвоение скрипта

Расширение pthreads

Для PHP есть многопоточное расширение [http://pthreads.org/ pthreads].

Оно не входит в ядро PHP, так что его нужно установить:

pecl install pthreads
## Расширение доступно в репозитории PECL и совместимо с ZTS

Простейший пример для проверки работоспособности расширения будет выглядеть так:


}

public function run(){

while(true){

echo “Worker {$this->i} ran” . PHP_EOL;

sleep(1);

}

}

}

for($i=0;$i<7;$i++){

**$workers[$i]=new workerThread($i);**

$workers[$i]->start();

}

?>
## Вывод номеров воркеров в 8 потоков

Использование сервера очередей

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

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

Самое главное

Выбор метода асинхронного выполнения полностью зависит от ваших задач. Но самыми производительными и надежными будут решения с использованием модуля PHP-FPM и сервера очередей.

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023