Страница 1 из 1

Мне бы чуточку асинхронности

Добавлено: 2019.07.01, 14:33
TopClans
Добрый день.
Для проекта в одном месте требуется быстрая отработка. Необходимо отправить по API запрос к 10-20 внешним серверам, принять ответ и вывести его пользователю. Сервера отвечают всегда с разной скоростью, поэтому пользователю нужно показывать ответы серверов по мере собственно получения ответов. Что-то вроде поиска билетов у Aviasales и подобных сервисах.

Знаю, PHP и Yii2 не для того созданы, но тем не менее есть такая потребность, всё остальное в проекте работает хорошо.

придумал 3 варианта, первый:
1) для каждого API создать свой контроллер
2) при необходимости пользователь делает запрос, на этой же странице с помощью AJAX идут запросы к каждому контроллеру
3) по мере получения ответов (все серверы отвечают с разной скоростью) с помощью JS заполняется табличка с ответами
Но в таком случае 10-20 раз запустится весь yii и даст ненужную нагрузку

другой вариант - создать REST API и делать всё примерно так же, но с использованием API - тогда, насколько я понимаю, будет использоваться меньше ресурсов (или нет?)

ну и третий вариант - вообще колхозный: вынести всю логику работы с этими внешними серверами в отдельное место, которое не будет связано с yii, которые будут только отвечать на запросы всё того же ajax.

Что можете посоветовать?

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.01, 15:33
proctoleha
Как вариант - использовать web socket. Не ajax

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.01, 16:08
TopClans
с веб сокетами я знаком, но не понимаю, как их в данном случае применить.
для начала нужно принять данные от пользователя, и потом их отправить запрос внешним серверам. я понимаю, что можно на стороне клиента "слушать" эти веб-сокеты, но важно максимально быстро отослать все запросы на внешние сервера. как помогут веб сокеты?

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.01, 17:12
proctoleha
При нажатии на кнопу принять данные, у вас отрабатывает js, который за этой кнопкой следит. И используете стандартный метод socket.send для отправки данных.
https://learn.javascript.ru/websockets

Например, вы передали socket.send("MyKey");

Сервер, который слушает нужный сокет, получает ключ, запускает стописят http клиентов, по завершении соединения каждый из них, также через сокет отсылает ответ.

Не?

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.01, 17:24
TopClans
понял, а в чем преимущество такого метода перед AJAX? использование веб-сокетов всё-таки усложнит разработку, а основное его преимущество, насколько я знаю - это то, что клиент может постоянно слушать сообщения от сервера. в моём случае в этом нет необходимости, нужен один запрос и один ответ.

но даже если и использовать сокеты, начальный вопрос всё же остаётся - как всё организовать?

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.01, 21:10
ElisDN
TopClans писал(а): 2019.07.01, 17:24 это то, что клиент может постоянно слушать сообщения от сервера. в моём случае в этом нет необходимости, нужен один запрос и один ответ.
Как раз и прилетят постепенно по одному сокетному соединению двадцать ответов вашему JS скрипту на странице.

А для Ajax, как вы и сказали, нужно двадцать запросов отправить и все с учётом тайм-аутов дождаться.

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.02, 06:45
ivanbcdef
Попробуйте Swoole, Redis pub/sub, WebSocket.

Вот: https://github.com/immusen/yii2-swoole-websocket.

Вообще в PHP как-то не очень много альтернатив для WebSocket. Ratchet и Swoole, кажись.

Я для этого использую Mojolicious.

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.03, 11:36
TopClans
ElisDN писал(а): 2019.07.01, 21:10
TopClans писал(а): 2019.07.01, 17:24 это то, что клиент может постоянно слушать сообщения от сервера. в моём случае в этом нет необходимости, нужен один запрос и один ответ.
Как раз и прилетят постепенно по одному сокетному соединению двадцать ответов вашему JS скрипту на странице.

А для Ajax, как вы и сказали, нужно двадцать запросов отправить и все с учётом тайм-аутов дождаться.
но мне не нужно постепенно, мне нужно чтобы запросы отправлялись асинхронно.
в вашем же варианте, насколько я понял, будет так: пользователь "даёт отмашку", и включается скрипт, который будет постепенно отправлять запросы на 20 серверов.каждый сервер отвечает примерно 1-2 секунды, постепенный опрос 20 серверов это минимум 20 секунд. да, первые результаты прилетят на страницу уже через 1-2 секунды, но ведь всё равно нужно ждать 20 секунд пока дойдёт очередь до последнего запроса на последний сервер.
и в то же время ajax может отправить 20 запросов одновременно, а не постепенно. да и принять он может 20 запросов. и теоретически через 1-2 секунды в ajax уже начнут поступать ответы на эти 20 запросов
разве я не прав?

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.03, 14:26
proctoleha
Вот пришла команда скрипту отправь 20 запросов.

Скрипт, например, из массива (или др. логика), берет адреса, команды, в цикле запускает 20 http клиентов, меньше чем за одну миллисекунду, после завершения запроса, каждый из http клиентов проталкивает через сокет ответ. На странице клиента js слушатель сокета их разруливает.

В случае с ajax читайте пост Дм. Елисеева

Разработка, конечно, усложнится, но цель, поставленная в первом посте, будет достигнута.

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.03, 16:29
ElisDN
TopClans писал(а): 2019.07.03, 11:36 но мне не нужно постепенно, мне нужно чтобы запросы отправлялись асинхронно.
в вашем же варианте, насколько я понял, будет так: пользователь "даёт отмашку", и включается скрипт, который будет постепенно отправлять запросы на 20 серверов.каждый сервер отвечает примерно 1-2 секунды, постепенный опрос 20 серверов это минимум 20 секунд. да, первые результаты прилетят на страницу уже через 1-2 секунды, но ведь всё равно нужно ждать 20 секунд пока дойдёт очередь до последнего запроса на последний сервер.
и в то же время ajax может отправить 20 запросов одновременно, а не постепенно. да и принять он может 20 запросов. и теоретически через 1-2 секунды в ajax уже начнут поступать ответы на эти 20 запросов
разве я не прав?
Я как раз и рассказал про общение с асинхронным сервером по одному вебсокету вместо двадцати Ajax-подключений к синхронному серверу.

Страница из JS отправляет один Ajax-запрос и висит на одном сокете. Сервер асинхронно/многопоточно/многопроцессно/как угодно одновременно отправляет свои 20 запросов и каждый этот процесс отправляет свой ответ в один и тот же канал вебсокета.

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

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.04, 23:26
TopClans
Сервер асинхронно/многопоточно/многопроцессно/как угодно одновременно отправляет свои 20 запросов и каждый этот процесс отправляет свой ответ в один и тот же канал вебсокета.
ну хоть убейте, не понимаю: в yii приходит один ajax-запрос, как его заставить выполнить 20 запросов одновременно?
или вы имеете в виду ситуацию, когда в качестве сервера выступает не yii, а что-то поддерживающее многопоточность, типа nodejs?

Re: Мне бы чуточку асинхронности

Добавлено: 2019.07.05, 00:02
ElisDN

Код: Выделить всё

foreach ($urls as $url) {
    exec("php yii parser/parse $url $userId > /dev/null &");
}

Re: Мне бы чуточку асинхронности

Добавлено: 2019.08.02, 18:08
TopClans
ElisDN писал(а): 2019.07.05, 00:02

Код: Выделить всё

foreach ($urls as $url) {
    exec("php yii parser/parse $url $userId > /dev/null &");
}
вот это мне и было нужно.
в результате использовал не совсем сокеты, а комет-сервер (получилось менее трудозатратно, а комет как раз идеально под мою задачу подошёл), и код выглядит так:

Код: Выделить всё

$out = Yii::getAlias('@app');
$ex = exec('php '.$out.'/yii controller > /dev/null &');
работает именно так, как и хотел. спасибо за помощь!

Re: Мне бы чуточку асинхронности

Добавлено: 2019.08.03, 14:20
kukuruku
TopClans писал(а): 2019.08.02, 18:08 вот это мне и было нужно.
в результате использовал не совсем сокеты, а комет-сервер (получилось менее трудозатратно, а комет как раз идеально под мою задачу подошёл), и код выглядит так:

Код: Выделить всё

$out = Yii::getAlias('@app');
$ex = exec('php '.$out.'/yii controller > /dev/null &');
работает именно так, как и хотел. спасибо за помощь!
а где тут комет?

Re: Мне бы чуточку асинхронности

Добавлено: 2019.09.25, 00:52
TopClans
kukuruku писал(а): 2019.08.03, 14:20 а где тут комет?
комет - в конце каждого из скриптов, которые запускаются в консоли. он отправляет сообщение на внешний comet сервер, а оттуда приходит сообщение в JS на сайте.
в контексте темы - мне нужна было просто возможность запустить несколько PHP скриптов одновременно, и о запуске через консоль я не задумывался, пока мне не подсказали.