【问题标题】:Are nested PHP includes CPU/memory intensive?嵌套 PHP 是否包含 CPU/内存密集型?
【发布时间】:2012-03-05 16:30:41
【问题描述】:

我正在用 PHP 编写一个网站,并通过将所有请求定向到一个 index.php 文件(使用 .htaccess)来获取“漂亮的 url”(也隐藏了我的目录)。然后索引文件解析 uri 并包含请求的文件。这些文件中还包含多个包含,每个都可能打开一个 MySQL 连接。然后 那些 文件也有包含,它们打开 sql 连接。它下降到大约 3-4 级。

此进程是否占用大量 CPU 和内存,包括 PHP 包含和打开(和关闭)每个包含文件中的 MySQL 连接?

另外,使用纯 htaccess 的漂亮 url 会使用更少的资源吗?

【问题讨论】:

    标签: php mysql .htaccess include cpu-usage


    【解决方案1】:

    PHP 开销

    将应用逻辑分解为源层次结构的答案取决于托管解决方案的方式。

    • 如果您使用专用主机/VM,那么您可能会使用 mod_php+Xcache 或等效项,答案将是:不,它不会真正影响运行时,因为所有内容都在 PHP 操作码级别缓存在内存中。
    • 如果您使用共享托管服务,那么它影响性能,因为任何 PHP 脚本都可能通过 PHP-cgi 加载,可能通过 suPHP 并且包含的​​整个源层次结构都需要读取并编译每个请求。更糟糕的是,在共享解决方案中,如果此请求是 1 分钟内的第一个请求,则服务器文件缓存将被刷新,并且编组此源将涉及大量物理 I/O = 秒时间延迟。

    我管理了几个 phpBB 论坛,发现通过聚合共享主机实现的常见包含层次结构,我可以将用户响应时间减半。这里有一些文章更详细地描述了这一点 (Terry Ellison [phpBB])。并引用一篇文章:

    让我用一些粗略的数字来量化我的观点。我需要强调的是,下面的数字是指示性的。我已将基准作为本文的附件包含在内,以防您想在自己的服务上验证它们。

    • 20–40。如果文件系统缓存未准备好,则每秒可以打开和读取的文件数。
    • 1,500–2,500。每秒可以打开和读取的文件数(如果文件系统缓存已使用其内容进行准备)。
    • 300,000–400,000。 PHP 解释器每秒可以编译的行数。
    • 20,000,000。 PHP 解释器每秒可以解释的 PHP 指令数。
    • 500-1,000。 PHP 解释器每秒可以调用的 MySQL 语句数,如果数据库缓存已使用您的表内容进行准备。

    有关更多信息,请参阅More on optimising PHP applications in a Webfusion shared service,您可以在其中复制基准测试以自己运行。

    MySQL 连接

    这里最简单的做法是连接连接。我使用我自己的 mysqli 类扩展,它使用标准的单对象每类模板。就我而言,任何模块都可以发出:

    $db = AppDB::get();
    

    返回这个对象。这很便宜,因为它是一个涉及六个 PHP 操作码的内部调用。

    另一种传统的方法是使用全局来保存对象,然后只做一个

    global $db;
    

    在任何需要使用它的函数中。

    小型应用程序的脚注

    您建议将所有包含合并到一个包含文件中。这对于稳定的生产来说是可以的,但在测试期间是一个痛苦。我可以建议一个简单的妥协吗?将它们分开以进行测试,但允许加载单个复合材料。您分两部分执行此操作 (i) 我假设每个包含都定义了一个函数或类,因此为每个包含使用标准模板,例如

    if( !function_exists( 'fred' ) ) {
        require "include/module1.php";
    }
    

    在主脚本中的任何加载之前,请执行以下操作:

    @include "include/_all_modules.php";
    

    这样,当您进行测试时,您会删除 _all_modules.php 并且脚本会退回到加载单个模块。当您高兴时,您可以重新创建_all_modules.php。您可以通过一个简单的“发布”脚本来完成这个服务器端,该脚本执行

    system( 'cp include/[a-z]*.php include/_all_modules.php' );
    

    这样,你可以两全其美

    【讨论】:

    • 感谢详细的回复!我在一个共享的环境中。尽管您链接到的文章看起来比我需要的信息多得多,但我从中得到的是我应该使用更少的包含,简化包含文件中的内容,并在整个请求期间使用一个连接。谢谢!
    • Yves,在 MySQL 连接上 +1。我还添加了一个精简的建议,用于汇总您可能会感到满意的包含内容。 :-)
    • 再次感谢特里。我一直在根据它们的功能将包含分离到文件中以便于调试,但是根据这里的建议,我正在考虑根据它们的使用频率重新排列它们。将所有常用方法放在一个文件中,将其他(并非在每个页面中使用的)方法放在一个或两个较小的文件中,以避免包含无论如何都不会使用的方法。
    【解决方案2】:

    这取决于 MySQL 客户端代码,我知道在打开具有相同参数的 MySQL 连接时,连接通常会被重用。

    我个人只会在前端控制器(你的 index.php 文件)中初始化数据库连接,因为无论如何一切都应该通过那里。

    【讨论】:

    • 这是一个很好的观点。通过.htaccess PHP 检查和解析以确定要包含的内容,您实际上是在两个不同的位置执行相同的工作两次。这将使您的代码更难维护。
    • 谢谢。那么,我将在整个请求过程中只打开一个连接。
    【解决方案3】:

    您可以使用include_once()require_once() 方法来确保PHP 只解析一次,从而节省处理时间。如果您怀疑您的代码可能会在每个脚本执行中多次尝试包含文件,这将特别有价值。

    http://php.net/manual/en/function.include-once.php

    我想使用 .htaccess 解析 URL 总是比任何其他方法使用更多的资源,纯粹是因为这些规则会在您的服务器遇到的每个 .php 文件请求时被激活。

    【讨论】:

    • 不完全是,如果您使用 -X 选项 strace apache2,那么您将看到处理 .htaccess 需要大约 2 毫秒。仅使用 <?php echo "hello world";?> 在共享托管服务(通常基于 suPHP)上需要大约 100 毫秒。 .htaccess 打开一个用户文件,而 PHP 通常打开几十个。
    猜你喜欢
    • 1970-01-01
    • 2012-07-12
    • 2011-02-21
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    相关资源
    最近更新 更多