Запуск параллельных скриптов PHP
У меня есть следующая проблема с моим сервером VPS.
У меня есть давно работающий PHP-скрипт, который отправляет большие файлы в браузер. Это что-то вроде этого:
<?php
header("Content-type: application/octet-stream");
readfile("really-big-file.zip");
exit();
?>
это в основном читает файл из файловой системы сервера и отправляет его в браузер. Я не могу просто использовать прямые ссылки (и позволить Apache обслуживать файл), потому что в приложении есть бизнес-логика, которая должна быть применена.
проблема в том, что пока такая загрузка запущенный сайт не отвечает на другие запросы.
6 ответов
проблемы связана с тем, что вы используете сессии. Когда сценарий имеет запущенный сеанс, он блокирует файл сеанса, чтобы предотвратить одновременную запись, которая может повредить данные сеанса. Это означает, что несколько запросов от одного клиента - с использованием одного и того же идентификатора сеанса - не будут выполняться одновременно, они будут поставлены в очередь и могут выполняться только по одному за раз.
несколько пользователей не будут испытывать эту проблему, так как они будут использовать другой сеанс идентификационная карточка. Это не означает, что у вас нет проблем, потому что вы можете захотеть получить доступ к сайту во время загрузки файла или установить загрузку нескольких файлов одновременно.
решение на самом деле очень простое: call session_write_close()
перед началом вывода файла. Это закроет файл сеанса, отпустит блокировку и позволит выполнять дополнительные параллельные запросы.
настройка сервера, вероятно, не единственное место, где вы должны проверять.
попробуйте сделать запрос из браузера, как обычно, а затем сделать другой из другого клиента.
либо wget с той же машины, либо другой браузер на другой машине.
каким образом сервер не отвечает на другие запросы? Это "ожидание example.com..." или это дает какую-либо ошибку?
Я делаю что-то подобное, но я обслуживаю файл с кусками, что дает файловой системе перерыв, в то время как клиент принимает и загружает кусок, что лучше, чем предлагать все сразу, что довольно требовательно к файловой системе и всему серверу.
EDIT: хотя это не ответ на этот вопрос, Аскер спросил о чтении файла поблочное. Вот функция, которую я использую. Укажите полный путь к файлу.
function readfile_chunked($file_path, $retbytes = true)
{
$buffer = '';
$cnt = 0;
$chunksize = 1 * (1024 * 1024); // 1 = 1MB chunk size
$handle = fopen($file_path, 'rb');
if ($handle === false) {
return false;
}
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
Я пробовал разные подходы (чтение и отправка файлов в небольшие куски [см. комментарий readfile
в PHP doc], используя PEARs HTTP_Download), но я всегда сталкивался с проблемами производительности, когда файлы становятся большими.
существует мод Apache X-Sendfile
где вы можете сделать свою бизнес-логику, а затем делегировать загрузку Apache. Загрузка не будет общедоступной. Я думаю, это самое элегантное решение проблемы.
больше Info:
то же самое происходит со мной, и я не использую сеансы. сессия.auto_start имеет значение 0 Мой пример сценария работает только " sleep (5)", и добавление" session_write_close () " в начале не решает проблему.
Проверьте httpd.файл conf. Возможно, у вас есть" KeepAlive On", и поэтому ваш второй запрос зависает, пока не будет завершен первый. Вообще ваш PHP скрипт не должен позволять посетителям долго ждать. Если вам нужно скачать что-то большое, сделайте это в отдельном внутреннем запросе, который пользователь не имеет прямого контроля. Пока это не сделано, верните некоторый статус" выполнение " конечному пользователю и, когда это сделано, обработайте фактические результаты.