Есть ли способ в PHP закрыть соединение (по сути, сказать браузеру, чем больше нет данных), но продолжить обработку. Конкретное обстоятельство, о котором я думаю, заключается в том, что я хотел бы обслуживать кэшированные данные, а затем, если срок действия кеша истек, я все равно буду обслуживать кэшированные данные для быстрого ответа, закрыть соединение, но продолжить обработку для восстановления и кэширования новых данные. По сути, единственная цель – сделать сайт более отзывчивым, поскольку не будет случайной задержки, пока пользователь ждет регенерации контента.
ОБНОВИТЬ:
PLUS имеет самый близкий ответ на то, что я искал. Чтобы уточнить пару людей, я ищу что-то, что позволяет выполнить следующие шаги:
ОБНОВИТЬ:
Это важно, это должно быть чисто PHP-решение. Установка другого программного обеспечения не является вариантом.
Если вы работаете под управлением fastcgi, вы можете использовать очень стильный:
fastcgi_finish_request ();
http://php.net/manual/en/function.fastcgi-finish-request.php
Более подробная информация доступна в двух экземплярах .
Я, наконец, нашел решение (спасибо Google, мне просто пришлось пытаться использовать разные комбинации поисковых запросов). Благодаря комментарию от arr1 на этой странице (это примерно две трети пути вниз по странице).
<?php ob_end_clean(); header("Connection: close"); ignore_user_abort(); // optional ob_start(); echo ('Text the user will see'); $size = ob_get_length(); header("Content-Length: $size"); ob_end_flush(); // Strange behaviour, will not work flush(); // Unless both are called ! // Do processing here sleep(30); echo('Text user will never see'); ?>
Мне еще предстоит проверить это, но вкратце. Вы отправляете два заголовка, один из которых сообщает браузеру, сколько данных ожидает, чтобы сообщить браузеру о закрытии соединения (которое он будет делать только после получения ожидаемого количества контента). Я еще не тестировал это, и я не знаю, что нужен sleep(30)
.
Вы можете сделать это, установив ограничение по времени на неограниченное и игнорируя соединение
<?php ignore_user_abort(true); set_time_limit(0);
см. также: http://www.php.net/manual/en/features.connection-handling.php
PHP не имеет такой настойчивости (по умолчанию). Единственный способ, о котором я могу думать, – запустить задания cron для предварительного заполнения кеша.
Насколько я знаю, если вы не используете FastCGI, вы не можете удалить соединение и продолжить выполнение (если только вы не получили ответ Endophage на работу, который я не смог). Так что вы можете:
Но становится все хуже. Даже если вы создаете дочерний процесс с proc_open()
, PHP будет ждать завершения до закрытия соединения даже после вызова exit()
, die()
, some_undefined_function_causing_fatal_error()
. Единственным обходным решением, которое я нашел, является создание дочернего процесса, который сам порождает дочерний процесс, например:
function doInBackground ($_variables, $_code) { proc_open ( 'php -r ' . escapeshellarg ("if (pcntl_fork() === 0) { extract (unserialize (\$argv [1])); $_code }") . ' ' . escapeshellarg (serialize ($_variables)), array(), $pipes ); } $message = 'Hello world!'; $filename = tempnam (sys_get_temp_dir(), 'php_test_workaround'); $delay = 10; doInBackground (compact ('message', 'filename', 'delay'), <<< 'THE_NOWDOC_STRING' // Your actual code goes here: sleep ($delay); file_put_contents ($filename, $message); THE_NOWDOC_STRING );
Для кэширования я бы так не сделал. Я бы использовал redis как свой кеш LRU . Это будет очень быстро (тесты), особенно когда вы скомпилируете его с клиентской библиотекой, написанной на C.
Когда вы устанавливаете очередь сообщений beanstalkd, вы также можете откладывать puts. Но я бы использовал redis brpop / rpush для выполнения другой очереди сообщений, потому что redis будет быстрее, особенно если вы используете PHP-клиентскую библиотеку (в C-пространстве пользователя).
в большинстве случаев этот параметр set_time_limit недоступен (из-за директивы safe-mode или max_execution_time
), чтобы установить 0, по крайней мере, когда на общем хостинге. Также общий хостинг действительно провайдеры не любят, чтобы пользователи долго удерживали процессы PHP. В большинстве случаев ограничение по умолчанию равно 30.
Используйте cron для записи данных на диск с помощью Cache_lite . Некоторые темы stackoverflow уже объясняют это:
Также довольно легко, но все же взломанный. Я думаю, что вы должны обновить (> VPS), когда вам нужно сделать такой взлом.
В качестве последнего средства вы можете сделать асинхронные запросы кэширования данных, например, с помощью Cache_lite. Имейте в виду, что для общего хостинга вам не нравится поддерживать много длительных PHP-процессов. Я бы использовал только один фоновый процесс, который вызывает другой, когда он достигает директивы max-execution-time
. Я хотел бы отметить время, когда начинается скрипт, и между несколькими вызовами кеша я буду измерять потраченное время, и когда он приблизится ко времени, когда я сделаю еще один асинхронный запрос. Я бы использовал блокировку, чтобы убедиться, что работает только один процесс. Таким образом, я не буду мочиться у провайдера, и это можно сделать. С другой стороны, я не думаю, что я напишу об этом, потому что это хакка, если вы спросите меня. Когда я доберусь до этой шкалы, я перейду на VPS.
Если вы делаете это для кэширования контента, вместо этого вы можете захотеть использовать существующее решение для кеширования, такое как memcached .
Нет. Что касается веб-сервера, запрос от браузера обрабатывается движком PHP, и все. Запрос длится до тех пор, как PHP.
Возможно, вы можете использовать fork()
.