Страницы

Поиск по вопросам

суббота, 8 февраля 2020 г.

Остановка выполнения цикла while

#comet #while #php #sleep #long_poll


Всем привет! Интересует вопрос - как можно правильно остановить выполнение while
цикла со sleep внутри. 
Дело в том, что я реализовываю "long poll" для быстрого обновления информации на
сайте (оповещения, другая информация).
СУТЬ РАБОТЫ СКРИПТА 
1. Мы отправляем GET-запрос на PHP-страницу в которой расположен скрипт.
2. Скрипт запускает цикл while.
3. В данном цикле существует 2 условия и sleep(1) в конце, который приостанавливает
выполнение цикла.
- Если если цикл работает больше 30 секунд - останавливаем выполнение цикла, соответственно
и скрипта. 
- Если на сайте появилась новая информация, скажем "оповещение" - выводим результат
пользователю и останавливаем цикл.
ПРОБЛЕМА 
Если пользователь закроет окно браузера, или же перезагрузит страницу - выполнится
новый запрос на данный скрипт, который запустит цикл повторно. Но при этом, предыдущие
выполнение  цикла while не остановятся, пока не сработает хотя бы одно условие внутри
него. Если же пользователь отошлет много запросов на страницу - память сервера начинает
сильно грузится и в результате все висит, пока все while не остановят свое выполнение.
ВОПРОС 
Как остановить выполнение цикла и скрипта в целом при повторном выполнении или же
перезагрузке страницы клиентом? 
Пока на данный момент я сделал следующее.
При выполнении скрипта мы генерируем рандомное число, которое записываем в переменную
и так же с сессию. Далее внутри while делаю условие, в котором данная переменная должна
равняться значению сессии. Если false - останавливаем цикл. 
Если мы запускаем скрипт по новой - значение сессии меняется и соответственно все
предыдущие выполнения while останавливаются. 
Можно ли использовать такой вариант? И на сколько он безопасен?
UPDATE.PHP
 // инициализируем сессию пользователя
 $session = Session::instance();

        $rand = rand();
        $session->set('user_update_key', $rand);
        $key = $rand;

        $limit = 20;
        $seconds = 0;

        set_time_limit($limit + 1);

        while (TRUE) {
            if (Session::instance()->get('user_update_key') == $key) {

                if (есть ли обновления. если есть - выводим) {
                    echo 'информация обновлений';
                    flush();
                    exit;
                }
                if ($seconds == $limit) { // завершаем выполнение цикла по истечению
времени.
                    echo 'Close';
                    flush();
                    exit;
                }
                $seconds++;
            } else {
                unset($session, $rand, $key, $notice, $mysession, $last_notice, $limit,
$notise_return, $seconds);
                flush();
                exit;
            }
            session_write_close();
            sleep(1);
            session_start();

}    


Ответы

Ответ 1



Похоже, вас интересует двусторонняя коммуникация пользователя с долгоиграющим процессом на PHP, и процессов PHP между собой во время их исполнения. PHP под это не заточен, как уже писали, но есть расширения, которые могут оказаться полезными. Без дополнительных примочек подходит механизм сессий, или же похожий собственный, задействующий, например, БД как "общую память". В первом приближении, я бы сделал точно то же, что и вы. Почему вы хотите именно long polling, а не новый разовый запрос раз в секунду? VK виджеты для комментариев, скажем, именно так работают. Если веб сервер настроен не закрывать мгновенно каждое соединение, то цепочка таких запросов не станет тормозить. (См. настройку KeepAlive для Apache) Наконец, можно посомтреть в сторону других технологий и протоколов, напр. Flash и RTMP: маленькая флешка в веб странице, которая по RTMP связывается с сервером RED5, и получает/отправляет инфу через JS коммуникацию с флешкой - настоящий риалтайм!

Ответ 2



Поищите другие варианты - как раз недавно на Хабре была статья о природе и ограничениях PHP. В комментариях предлагаются и другие варианты. Например, в этом и в этом.

Ответ 3



Ну как вариант, записать время в куки , и недавать юзеру выполнять следующий запрос пока тот не выполнится......

Комментариев нет:

Отправить комментарий