繁体   English   中英

运行并发PHP脚本

[英]Running concurrent PHP scripts

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

我有一个长期运行的PHP脚本,它将大文件发送到浏览器。 它执行以下操作:

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

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

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

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

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

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

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

尝试照常从浏览器发出请求,然后再从其他客户端发出另一个请求。

从同一台计算机上的wget或另一台计算机上的另一个浏览器。

服务器不以什么方式响应其他请求? 是“正在等待example.com ...”还是给出任何错误?

我做类似的事情,但我将文件分块处理,这使文件系统在客户端接受并下载块时有所中断,这比一次提供全部内容要好,这对文件系统和整个服务器。

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

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

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

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

我尝试了不同的方法(使用PEARs HTTP_Download读取和发送小块文件(请参见PHP文档中有关readfile注释),但是当文件变大时,我总是会遇到性能问题。

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

更多信息:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM