Запуск параллельных скриптов 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 скрипт не должен позволять посетителям долго ждать. Если вам нужно скачать что-то большое, сделайте это в отдельном внутреннем запросе, который пользователь не имеет прямого контроля. Пока это не сделано, верните некоторый статус" выполнение " конечному пользователю и, когда это сделано, обработайте фактические результаты.