运行并发PHP脚本

时间:2012-01-17 11:41:45

标签: php apache concurrency

我的VPS服务器出现以下问题。

我有一个长期运行的PHP脚本,可以将大文件发送到浏览器。它做了这样的事情:

<?php
header("Content-type: application/octet-stream");
readfile("really-big-file.zip");
exit();
?>

这基本上从服务器的文件系统中读取文件并将其发送到浏览器。我不能只使用直接链接(并让Apache提供文件),因为应用程序中存在需要应用的业务逻辑。

问题是,当此类下载正在运行时,该站点不会响应其他请求。

6 个答案:

答案 0 :(得分:33)

您遇到的问题与您使用会话的事实有关。当脚本具有正在运行的会话时,它会锁定会话文件以防止可能损坏会话数据的并发写入。这意味着来自同一客户端的多个请求 - 使用相同的会话ID - 将不会同时执行,它们将排队并且一次只能执行一个。

多个用户不会遇到此问题,因为他们将使用不同的会话ID。这并不意味着您没有问题,因为您可能想要在下载文件时访问该站点,或者一次下载多个文件。

解决方案实际上非常简单:在开始输出文件之前调用session_write_close()。这将关闭会话文件,释放锁并允许执行进一步的并发请求。

答案 1 :(得分:2)

您的服务器设置可能不是您应该检查的唯一地方。

尝试照常从浏览器处执行请求,然后从其他客户端执行另一项请求。

来自同一台机器的wget或另一台机器上的其他浏览器。

答案 2 :(得分:1)

服务器以何种方式响应其他请求?是“等待example.com ......”还是会出现任何错误?

我做了类似的事情,但我提供了chunked文件,这使得文件系统在客户端接受并下载一个块时会中断,这比一次提供整个文件要好,这对文件要求很高系统和整个服务器。

编辑:虽然不是这个问题的答案,但是提问者询问了阅读文件的问题。这是我使用的功能。提供文件的完整路径。

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;
}

答案 3 :(得分:0)

我尝试了不同的方法(使用PEARs HTTP_Download读取和发送小块文件[参见PHP文档中readfile的评论])但是当文件变大时我总是遇到性能问题。< / p>

有一个Apache mod X-Sendfile,您可以在其中执行业务逻辑,然后将下载委派给Apache。下载将不会公开。我认为,这是解决问题的最佳方案。

更多信息:

答案 4 :(得分:0)

同样的事情发生在我身上,我没有使用会话。 session.auto_start设置为0 我的示例脚本只运行“sleep(5)”,并且在开头添加“session_write_close()”并不能解决问题。

答案 5 :(得分:0)

检查您的httpd.conf文件。也许你有“KeepAlive On”,这就是为什么你的第二个请求会挂起,直到第一个请求完成。通常,您的PHP脚本不应允许访问者等待很长时间。如果您需要下载大量内容,请在用户无法直接控制的单独内部请求中执行此操作。在完成之前,将一些“执行”状态返回给最终用户,并在完成后处理实际结果。